poj 3270 置换群
题意:一个数列,每次可交换两个数,交换的代价为这两个数的和,要把这些数按升序排列,问最小的代价?
分析:对于任意循环i,设长度为ki,则至少交换ki-1次,即每次让一个元素到达正确位置,第ki-1个到达后,第ki个自然也在正确位置。一种方法是让最小元素ti参加所有交换,其它元素各参加一次,总代价为:sum(i)+(ki-2)*ti, sum(i)为循环i所有元素之和。 另一种方法是让ti和n个数中最小的数m交换,然后m和循环里的其它数交换,最后再让m和ti交换,总代价为:sum(i)+ti+(ki+1)*m,最终答案为两种代价的较小者。。
const int maxn=10005; struct node{ int val,id; }e[maxn]; bool cmp(node e1,node e2){ return e1.val<e2.val; } int n,b[maxn],sm=-1,ans; int solve(int i){ int k=1,sum=e[i].val,t=e[i].val; b[i]=1; for(int j=e[i].id;j!=i;j=e[j].id){ b[j]=1; checkmin(t,e[j].val); sum+=e[j].val; k++; } return sum+ min((k-2)*t,t+(k+1)*sm); } int main(){ scanf("%d",&n); FOR(i,0,n){ scanf("%d",&e[i].val); e[i].id=i; checkmin(sm,e[i].val); } sort(e,e+n,cmp); FOR(i,0,n){ if(b[i]||e[i].id==i) continue; ans+=solve(i); } printf("%d\n",ans); return 0; }