首页 > 代码库 > poj 3270 置换

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 }