题目:http://uva.onlinejudge.org/external/10/1016.pdf
题意:就是将一个排列通过不断的交换两个数的位置,使得排列变成{1,2,3,4.....n}交换两个数的cost是交换的两个数的和。
思路:首先,我们能得到一个排列。然后根据置换得到一个一个的环。在每个环内,因为最小的数肯定不再自己的位置上,那么我们把那个最小数的位置应该放的数换到过来,直到最小的数在自己的位置。这样对于一个环来讲是最优的。 但是仅仅这样是不够的,我们可能会将所有数中的最小值跟这个环内的最小值换一下位置,这样就能让全部的最小值加入这个环中,然后按照之前的做法,看下哪种代价比较小。具体可以看代码。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define rrep(i,b,a) for(int i = (b); i >= (a); --i)
#define clr(a,x) memset(a,x,sizeof(a))
#define eb emplace_back
const int maxn = 1000 + 5;
int a[maxn], p[maxn], pos[maxn];
bool vis[maxn];
vector<int> id;
int n;
int ID(int x) { return lower_bound(id.begin(),id.end(),x) - id.begin(); }
int main()
{
#ifdef ACM
freopen("in.txt","r",stdin);
#endif // ACM
int cas = 0;
while (scanf("%d",&n)==1 && n) {
id.clear();
id.eb(-1);
rep(i,1,n+1) {
scanf("%d",a+i);
id.eb(a[i]);
}
sort(id.begin(),id.end());
id.erase(unique(id.begin(),id.end()),id.end());
rep(i,1,n+1) {
p[i] = ID(a[i]);
pos[p[i]] = i;
}
int ans = 0;
clr(vis,0);
rep(i,1,n+1) if (!vis[i]) {
int rt = i;
vector<int> cir;
while (!vis[rt]) {
vis[rt] = true;
cir.eb(rt);
rt = p[rt];
}
sort(cir.begin(),cir.end());
if (cir.size() == 1) continue;
int min_cost = 0;
for(auto j : cir) min_cost += id[j];
min_cost += ((int)cir.size() - 2) * id[cir[0]];
if (cir[0] != 1) {
int cost = id[cir[0]] + id[1];
cir.insert(cir.begin(),1);
for(auto j : cir) cost += id[j];
cost += ((int)cir.size() - 2) * id[cir[0]];
min_cost = min(min_cost,cost);
}
ans += min_cost;
}
++cas;
printf("Case %d: %d\n\n",cas,ans);
}
}