poj 3270 置换
1 poj 3270 置换的应用 黑书原题P248 2 /** 3 题意: 给定序列, 将其按升序排列, 每次交换的代价是两个数之和, 问代价最小是多少 4 思路:1、对于同一个循环节之内的,肯定是最小的与别的交换代价最小 5 2、 对于整个序列中最小的与其交换 ,也可能最小 6 比较这两个大小,即可得出结论 7 对于情况1:代价为 sum+(len-2)*t //len 为每个循环节的长度, t 为每个循环节中最小的那个数 sum 为循环节中所 有数的和 8 对于情况2: 代价: sum+t+(len+1)*min // m为整个序列中最小的数 9 **/ 10 11 #include <iostream> 12 #include <cstring> 13 #include <cstdio> 14 using namespace std; 15 int n,Max,Min; 16 const int maxn = 10005; 17 bool vis[maxn]; 18 int num[maxn],pos[maxn*10]; 19 20 void countSort(){ 21 Max = -maxn*10; 22 Min = maxn*10; 23 memset(pos,0,sizeof(pos)); 24 for(int i=1;i<=n;i++){ 25 pos[num[i]] =1; 26 if(num[i]<Min) Min = num[i]; 27 if(num[i]>Max) Max = num[i]; 28 } 29 for(int i=1;i<=Max;i++){ 30 pos[i] += pos[i-1]; 31 } 32 } 33 34 int solve(){ 35 int ans =0; 36 memset(vis,0,sizeof(vis)); 37 for(int i=1;i<=n;i++){ 38 int len =0,temp = i,sum =0,tMin = maxn*10; 39 while(!vis[temp]){ 40 vis[temp] = true; 41 len ++; 42 sum += num[temp]; 43 if(num[temp]<tMin) tMin = num[temp]; 44 temp = pos[num[temp]]; 45 } 46 if(len>0){ 47 int res1 = sum + (len-2)*tMin,res2 =sum + tMin+ (len+1)*Min; 48 ans += res1<res2?res1:res2; 49 } 50 } 51 return ans; 52 } 53 54 int main() 55 { 56 int i; 57 scanf("%d",&n); 58 for(i=1;i<=n;i++) 59 scanf("%d",&num[i]); 60 countSort(); 61 printf("%d\n",solve()); 62 63 return 0; 64 }