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 }
poj 3270 置换
时间: 2024-11-06 06:35:13