18.12.11 DSA 排序的代价
描述
现有一排装满货物的箱子,重量各不相同(都已标示在箱子上),为了进行后面的工作,需要将这些箱子按轻重有序放置,但只有一名工作人员来完成这项工作,由于空间有限,他只能通过不断交换两个箱子(可不相邻)的位置的方式来实现箱子的排序。他知道这样一定可以完成任务,但搬箱子很累,所以他希望找到一种最省力的方式来完成工作,假设一次交换两个箱子的代价为这两个箱子的重量之和,那么这项工作的总代价为此过程中所有“交换”的代价之和,请帮助他计算排列这些箱子的最小代价。
输入输入包含多个数据实例,每个实例独占一行,每行数据是以空格分隔的非负整数,其中第一个整数表示箱子的个数(n),接下来为n个不同的正整数,分别表示n个箱子的重量,其顺序表示了箱子的初始顺序;当n=0时表示输入结束。输出对每个有效数据实例(n!=0)都输出一个整数,独占一行,表示该实例中排序箱子的最小代价。
样例输入
3 3 2 1
4 8 1 2 4
5 1 8 9 7 6
6 8 4 5 3 2 7
0
样例输出
4
17
41
34
提示
示例解释:
共有4个有效数据实例:
第一个数据实例为3 2 1,通过交换重为3和1的箱子即可,总代价为3+1=4;
第二个数据实例为8 1 2 4,代价最小的交换过程为
1↔2,1↔4,1↔8,总代价为(1+2)+(1+4)+(1+8) = 17;
第三个数据实例为1 8 9 7 6,代价最小的交换过程为
1↔6,1↔9,1↔7,1↔8,1↔6,总代价为(1+6)+(1+9)+(1+7)+(1+8)+(1+6)=41;
第四个数据实例为8 4 5 3 2 7,代价最小的交换过程为
3↔5,3↔4,2↔7,2↔8,总代价为(3+5)+(3+4)+(2+7)+(2+8)=34。
请注意边界条件和IO,n可能很大。
题解1(使用STL)
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <stack> 5 #include <string> 6 #include <math.h> 7 #include <queue> 8 #include <stdio.h> 9 #include <string.h> 10 #include <vector> 11 #include <fstream> 12 #define maxn 200005 13 #define inf 999999 14 #define cha 127 15 using namespace std; 16 17 int n, allsize, Min; 18 struct node { 19 int val, idx; 20 }; 21 bool cmp(node a1, node a2) { 22 return a1.val < a2.val; 23 } 24 node box[maxn]; 25 int towhere[maxn]; 26 bool visited[maxn]; 27 28 void mysort() { 29 sort(box + 1, box + 1 + n, cmp); 30 for (int i = 1; i <= n; i++) 31 towhere[box[i].idx] = i; 32 } 33 34 int solvealoop(int s) { 35 int first = s, loopmin = inf, sum = 0, count = 0; 36 while (visited[first] == false) { 37 visited[first] = true; 38 int val = box[first].val; 39 loopmin = min(val, loopmin); 40 sum += val; 41 first = towhere[first]; 42 count++; 43 } 44 int val1 = loopmin * (count-2), val2 = loopmin + Min + Min * count; 45 if (val1 < val2) 46 sum += val1; 47 else sum += val2; 48 return sum; 49 } 50 51 void init() { 52 memset(visited, 0, sizeof(visited)); 53 Min = inf; 54 for (int i = 1; i <= n; i++) 55 { 56 scanf("%d", &box[i].val); 57 box[i].idx = i; 58 Min = min(box[i].val, Min); 59 } 60 mysort(); 61 int ans = 0; 62 for (int i = 1; i <= n; i++) 63 if (visited[i] != true) 64 ans+=solvealoop(i); 65 printf("%d\n", ans); 66 } 67 68 int main() 69 { 70 while (scanf("%d", &n) && n) 71 init(); 72 return 0; 73 }
题解2(不使用STL)
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <stack> 5 #include <string> 6 #include <math.h> 7 #include <queue> 8 #include <stdio.h> 9 #include <string.h> 10 #include <vector> 11 #include <fstream> 12 #define maxn 200005 13 #define inf 999999 14 #define cha 127 15 using namespace std; 16 17 int n, allsize, Min; 18 struct node { 19 int val, idx; 20 }; 21 bool cmp(node a1, node a2) { 22 return a1.val < a2.val; 23 } 24 node box[maxn]; 25 int towhere[maxn]; 26 bool visited[maxn]; 27 28 void mysort() { 29 sort(box + 1, box + 1 + n, cmp); 30 for (int i = 1; i <= n; i++) 31 towhere[box[i].idx] = i; 32 } 33 34 int solvealoop(int s) { 35 int first = s, loopmin = inf, sum = 0, count = 0; 36 while (visited[first] == false) { 37 visited[first] = true; 38 int val = box[first].val; 39 loopmin = min(val, loopmin); 40 sum += val; 41 first = towhere[first]; 42 count++; 43 } 44 int val1 = loopmin * (count-2), val2 = loopmin + Min + Min * count; 45 if (val1 < val2) 46 sum += val1; 47 else sum += val2; 48 return sum; 49 } 50 51 void init() { 52 memset(visited, 0, sizeof(visited)); 53 Min = inf; 54 for (int i = 1; i <= n; i++) 55 { 56 scanf("%d", &box[i].val); 57 box[i].idx = i; 58 Min = min(box[i].val, Min); 59 } 60 mysort(); 61 int ans = 0; 62 for (int i = 1; i <= n; i++) 63 if (visited[i] != true) 64 ans+=solvealoop(i); 65 printf("%d\n", ans); 66 } 67 68 int main() 69 { 70 while (scanf("%d", &n) && n) 71 init(); 72 return 0; 73 }
碎碎念
一开始用索引排序做(题解2)!我是傻子!是太想套书上内容了吗……跑出来的时间真恐怖,还好DSA对时间要求不高也过了
思路
有点像索引排序里面的那个替换循环……在每个循环里面每次只用循环里最小的那个值跟其他值交换(最小值现在在哪就跟应该到那的那个值交换)
但有时候环里的值都太大了……大到甚至把整个数组里的最小值跟环里的最小值换一下然后用这个值作为环里的最小值做交换最后做完再换回去都比原来的情况要好……
写起来还是不难的……但是这个思路只能靠着给的几个样例连蒙带猜才能想到,是我太菜了