uva 1016 - Silly Sort(置换的灵活应用)

来源:互联网 发布:java 统计一年月消费 编辑:程序博客网 时间:2024/06/04 23:28

题意:给你n个不同数,可以进行一种操作,交换任意两个数的位置,则花费为两数的和,求把原序列变为严格单调递增的序列的最小花费


解析:通过置换可以发现原序列可以分为多个周期(循环)的变换,如8 4 5 3 2 7 变为(8 2 7)和(4 3 5),对于每个周期,所有数都不在他升序后的位置,即所有的数都需要交换,每次用周期内最小的数与另一个数交换,设这个周期的最小值为min,数量为size,所有数的和为sum ,则易得最小花费为min*(size-1)+sum-min,这样得到的花费就是最小值了

但需注意的是在进行变换时,我们可以先把 所有数的最小值Min 和min先交换,当这个周期成升序后再交换回来,则花费为2*(min+Min)+sum-min+(size-1)*Min  比较两者最小值即答案


//保存周期

#include<iostream>#include<cstdio>#include<math.h>#include<string.h>#include<algorithm>#include<vector>using namespace std;#define N 10005int k,n,a[N],c[N],b[N],vis[N],minx;long long res;vector<int> w[N];void inint(){    int i,j;    minx=N*2;    for(i=0;i<N;i++)     w[i].clear();    for(i=0; i<n; i++)    {        scanf("%d",&a[i]);        c[i]=a[i];    }    sort(c,c+n);    minx=c[0];    for(i=n-1; i>=0; i--)    {        b[c[i]]=a[i];    }    memset(vis,0,sizeof(vis));    for(i=0; i<n; i++)    {        j=c[i];        while(!vis[j])        {            vis[j]=1;            w[k].push_back(j);            j=b[j];        }        k++;    }}int main(){   // freopen("in.txt","r",stdin);   // freopen("outw.txt","w",stdout);    int i,j,s,min,qq=0,t=0;    while(~scanf("%d",&n)&&n)    {        res=k=0;        inint();        for(i=0; i<k; i++)        {           s=w[i].size();           if(s<=1) continue;           min=2*N;           for(j=0;j<s;j++)           {             res+=w[i][j];             if(w[i][j]<min) min=w[i][j];           }            res-=min;           if(min!=minx&&min*(s-1)>(s+1)*minx+2*min)            res+=(s+1)*minx+2*min;           else res+=(s-1)*min;        }        t++;       // if(t>=2) puts("");        printf("Case %d: %lld\n\n",t,res);    }    return 0;}

//直接求答案 快些

#include <iostream>#include <cstdio>#include <map>#include <algorithm>using namespace std;int a[100000];int b[100000];bool vis[100000];int main (void){    // freopen("in.txt","r",stdin);   // freopen("out.txt","w",stdout);    int N;    int t = 0;    while (~scanf("%d", &N) && N)    {        t++;        for (int i = 0; i < N; ++i)        {            scanf("%d", &a[i]);            b[i] = a[i];            vis[i] = false;        }        sort(b, b + N);        // Map the numbers to their desired place after sort        map<int, int> place;        for (int i = 0; i < N; ++i)        {            place[b[i]] = i;        }        int res = 0;        for (int i = 0; i < N; ++i)        {            if (vis[i] == false)            {                if (place[a[i]] == i)                {                    vis[i] = true;                    continue;                }                // We're in new cycle                int min_val = a[i];                int num = 0;                int sum = 0;                int j = i;                while (vis[j] == false)                {                    sum += a[j];                    num++;                    if (a[j] < min_val)                    {                        min_val = a[j];                    }                    vis[j] = true;                    j = place[a[j]];                }                sum -= min_val;                res += sum ;                // Let's try to borrow the minimum value.                // If it's less costly then update our result.                if (2 * (b[0] + min_val) <(min_val - b[0]) * (num - 1))                {                    res += ( b[0]) * (num - 1) +2 * (b[0] + min_val);                }                else res+=(num-1)*min_val;            }        }        printf("Case %d: %d\n\n", t, res);    }    return 0;}


原创粉丝点击