1 poj 3270 置換的應用 黑書原題P248 2 /** 3 題意: 給定序列, 將其按升序排列, 每次交換的代價是兩個數之和, 問代價最小是多少 4 思路:一、對於同一個循環節以內的,確定是最小的與別的交換代價最小 5 二、 對於整個序列中最小的與其交換 ,也可能最小 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 }