题目描述
小C有一个N个数的整数序列,这个序列的中的数两两不同。小C每次可以交换序列中的任意两个数,代价为这两个数之和。小C希望将整个序列升序排序,问小C需要的最小代价是多少?
输入输出格式
输入格式:
第一行,一个整数N。
第二行,N个整数,表示小C的序列。
输出格式:
一行,一个整数,表示小C需要的最小代价。
输入输出样例
输入样例#1: 复制
6 8 4 5 3 2 7
输出样例#1: 复制
34
说明
数据范围:
对于30%的数据,1<=N<=10;
对于全部的数据,1<=N<=100000,输入数据中的其他整数均为正整数且不超过109。
分析:很显然的贪心。因为每次只能交换两个数,那么每次都拿小的数来交换肯定会更优。但肯定不会这么简单。首先从样例分析,样例中的8,2,7这三个数只要互相交换就可以到达目标位置,也就是说这三个数形成了一个“环”,那么每次就照这样的环,将环中的每一个数归位的最小花费只有两种情况:要么就每次都拿环中最小的数与每一个数相互交换,要么就拿整个序列中最小的数与环中每个数交换。不过要注意,第二种情况交换的时候有一个数会交换两次(可以自己模拟一下),那么肯定就将环中最小的数交换两次最优。具体看代码:
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<iostream> 6 #include<iomanip> 7 #include<algorithm> 8 using namespace std; 9 const int N=1e5+7; 10 int n; 11 bool vis[N]; 12 long long ans; 13 struct Node{ 14 int val,pos; 15 }a[N]; 16 inline int read() 17 { 18 char ch=getchar();int num=0;bool flag=false; 19 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)flag=true;ch=getchar();} 20 while(ch>=‘0‘&&ch<=‘9‘){num=num*10+ch-‘0‘;ch=getchar();} 21 return flag?-num:num; 22 } 23 bool cmp(Node x,Node y) 24 {return x.val<y.val;} 25 inline void work(int x) 26 { 27 long long tot=0,num=0,minn=1e9+7; 28 while(!vis[x]){ 29 vis[x]=true;tot++; 30 num+=a[x].val; 31 if(a[x].val<minn) 32 minn=a[x].val; 33 x=a[x].pos;} 34 long long a1=num+(tot-2)*minn; 35 //第一种情况最小的数只需要交换tot-1次 36 long long a2=num+(tot+1)*a[1].val+minn; 37 //第二种情况,如果用整个序列中最小的数交换则需交换(tot-1)次 38 ans+=min(a1,a2); 39 } 40 int main() 41 { 42 n=read(); 43 for(int i=1;i<=n;i++){ 44 a[i].val=read(); 45 a[i].pos=i;} 46 sort(a+1,a+n+1,cmp); 47 for(int i=1;i<=n;i++) 48 if(!vis[i]) 49 work(i); 50 printf("%lld",ans); 51 return 0; 52 }
原文地址:https://www.cnblogs.com/cytus/p/8929775.html
时间: 2024-12-14 15:30:14