codevs 2845 排序的代价

/*
比较简单的置换群题
首先排成升序 每个元素都有想去的位置
先找轮换 比如1->2 2->3 3->1 那么(1.2.3)就是一个轮换
可以看出他们之间互不影响 然后开始处理每个轮换
可以用数学归纳法证明处理每个小的需要最少换n-1次
为了让代价最小我们那c最小的元素当做中间值
这里有反例 就是如果有一个c很小的数
我们先把这个轮换里的min和这个交换 然后拿这个完成n-1次
最后再换回来 这样可能更优 所以min一下就好了 
(讲的太不详细了 具体的可以仔细的上网学习一下) 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1010
#define inf 0x3f3f3f3f
using namespace std;
int n,f[maxn],ans,cas,sum,mii,Mii,cnt;
struct node{
    int c,to;
    bool operator < ( const node & x ) const {
        return c<x.c;
    }
}p[maxn];
void Clear(){
    memset(f,0,sizeof(f));
    Mii=inf;ans=0;
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        Clear();
        for(int i=1;i<=n;i++){
            scanf("%d",&p[i].c);
            Mii=min(Mii,p[i].c);
            p[i].to=i;
        }
        sort(p+1,p+1+n);
        for(int i=1;i<=n;i++)
            if(!f[i]){
                sum=0;mii=inf;cnt=0;
                int r=i;
                while(!f[r]){
                    mii=min(mii,p[r].c);
                    sum+=p[r].c;cnt++;
                    f[r]=1;r=p[r].to;
                }
                ans+=sum+min((cnt-2)*mii,(cnt+1)*Mii+mii);
            }
        if(ans==0)break;
        printf("Case %d: %d\n",++cas,ans);
    }
    return 0;
}

 

posted @ 2016-09-12 14:51  一入OI深似海  阅读(213)  评论(0编辑  收藏  举报