链接:https://ac.nowcoder.com/acm/contest/554/I
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

坑坑作为一个ACMer,经常要对一组数字进行排序,在排序过程中,将两个数字交换位置的花销是这两个数字的和,慢慢的他想实现一种最低花销的排序方式,你们能帮助他吗?

 

输入描述:

输入包含多组测试数据。
每组测试输入包含一组数字包含的整数个数n以及n个整数mi(1<=n<1000,0<=mi<=10000)给定的整数互不重复。

输出描述:

对于每组测试数据,输出一个整数,给定整数按升序排序时所需花销的最小值。

示例1

输入

复制

4
3 1 5 4 

输出

复制

13

将需要排序的数 原先的位置和末尾的位置用有向边连接

会发现其实其实就是一个个闭环

我们只需要将每个闭环都按照最低的权值处理

一共有两种方法

1.第一种就是有闭环中最小的数一次次替换

2.就是将闭环外最小的数与闭环内最小的数交换,再用闭环外最小的数对闭环内其他的数进行交换,最后将闭环内最小的数换回

保证权值最小的方法一定是二者之一

由此代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int sum=0;
int cnt=0;
int a[1005];
int b[1005];
int pos[1005];
int vis[1005];
int Min;
void dfs(int x)
{
    if(vis[x]==1) return ;
    Min=min(Min,a[x]);
    cnt++;
    sum+=a[x];
    vis[x]=1;
    dfs(pos[x]);
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(vis,0,sizeof(vis));
        int ans=0;
        int MIN=1e9;
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]),b[i]=a[i],MIN=min(MIN,a[i]);
        sort(b+1,b+1+n);
        for(int i=1; i<=n; i++)
            pos[i]=lower_bound(b+1,b+1+n,a[i])-b;
        for(int i=1; i<=n; i++)
        {
            Min=1e9;
            sum=0;
            cnt=0;
            if(vis[i]==0)
            {
                dfs(i);
                //cout<<"{"<<sum<<" "<<cnt<<" "<<pos[i]<<" ";
                int tmp=min(sum-Min+(cnt-1)*Min,sum+Min+(cnt+1)*MIN);
                //cout<<i<<" "<<tmp<<"}"<<endl;
                //int tmp=sum-Min+(cnt-1)*Min;
                ans+=tmp;
            }
        }
        printf("%d\n",ans);
    }
}