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;
}

 

posted @ 2013-05-26 22:30  心向往之  阅读(109)  评论(0编辑  收藏  举报