POJ3270 Cow Sorting

解法:置换。

题目链接:http://poj.org/problem?id=3270

  • 1.找出初始状态和目标状态。明显,目标状态就是排序后的状态。 
  • 2.画出置换群,在里面找循环。例如,数字是8 4 5 3 2 7 
  • 明显,目标状态是2 3 4 5 7 8,能写为两个循环: 
  • (8 2 7)(4 3 5)。 
  • 3.观察其中一个循环,明显地,要使交换代价最小,应该用循环里面最小的数字2,去与另外的两个数字,7与8交换。这样交换的代价是: 
  • sum - min + (len - 1) * min 
  • 化简后为: 
  • sum + (len - 2) * min 
  • 其中,sum为这个循环所有数字的和,len为长度,min为这个环里面最小的数字。 
  • 4.考虑到另外一种情况,我们可以从别的循环里面调一个数字,进入这个循环之中,使交换代价更小。例如初始状态: 
  • 1 8 9 7 6 
  • 可分解为两个循环: 
  • (1)(8 6 9 7),明显,第二个循环为(8 6 9 7),最小的数字为6。我们可以抽调整个数列最小的数字1进入这个循环。使第二个循环变为:(8 1 9 7)。让这个1完成任务后,再和6交换,让6重新回到循环之后。这样做的代价明显是: 
  • sum + min + (len + 1) * smin
  • 其中,sum为这个循环所有数字的和,len为长度,min为这个环里面最小的数字,smin是整个数列最小的数字。 
  • 5.因此,对一个循环的排序,其代价是sum - min + (len - 1) * min和sum + min + (len + 1) * smin之中小的那个数字。
  • 考虑到需要每个循环的所有数字的和, 其实就是加上这个数列的所有数的和即可,还需要找到所有数中的最小值,每次去找一个循环,维护他的最小值即可。
  • #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    #include<math.h>
    #define nn 10010
    #define inf 0x7fffff
    using namespace std;
    struct node
    {
        int num,id;
    }a[nn];
    int b[nn];
    bool cmp(node x,node y)
    {
        return x.num<y.num;
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            int minn=inf;//数列的最小值
            int sum=0;
            for(int i=0;i<n;i++)
            {
                scanf("%d",&b[i]);
                sum+=b[i];
                a[i].num=b[i];
                a[i].id=i;
                minn=minn<b[i]?minn:b[i];
            }
            sort(a,a+n,cmp);
            for(int i=0;i<n;i++)
            {
                int t;
                if(b[i]!=-1)
                {
                    int cont=1;
                    t=b[i];
                    int d=a[i].id;
                    if(b[d]<t)
                        t=b[d];
                    while(d!=i)
                    {
                        cont++;
                        d=a[d].id;
                        t=b[d]<t?b[d]:t;//记录该循环的最小值
                    }
                    int v=(cont-2)*t;
                    int w=(cont+1)*minn+t;
                    sum+=v<w?v:w;
                    b[i]=-1;
                }
            }
            cout<<sum<<endl;
        }
        return 0;
    }
    

    赶脚这道题和HDU2838的一样的,只是HDU的数据范围是10^5,其他的都一样吧!,这个交HDU会TLE,能过HDU的交POJ会WA抓狂,有种不能愉快的玩耍的赶脚!
     


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值