lnsyoj91【USACO07FEB】cow sorting牛排序

置换环理论

以本题为例子

原序列:2 3 4 1 6 5
排序后:1 2 3 4 5 6

这个序列可以找到两个单独的置换环{ {1, 2, 3, 4} {5, 6} },就是几个数通过几次交换到达排好序正确的位置不需要与其他数交换。显然这样是最优的,可以发现,若一个置换环中有n个元素,则可以通过n-1次交换使得这n个元素归位。那么总的交换次数就是置换环的数量-1。
结论是:最少交换次数就是总元素的个数-置换环的数量。
至于证明嘛,这样显然是最优的。因为每个置换环相互独立,互不干扰,而每一个置换环所需最少交换次数又是元素个数-1(这也是显然的),不可能再少了,所以这样就是最少的。

那么我们再来看一下本题
假设置换环长度为n,很显然对于每个置换环要移动某个数字(n-1)次才可以让置换环中所有数字有序,所以一定是移动数值最小的那个吗? 但是不一定,因为你可以先将那个最小的数和整个序列中最小的数交换,排完序后再换回来,这样有可能更优,所以对于每个置换环需要判断一下。

ans+=min(s[i].val*(cnt-1)+sum,s[1].val*(cnt-1)+sum+2*(s[1].val+s[i].val));

这里的s[1].val就是数值最小的那个,2*(s[1].val+s[i].val)就是要先交换s[i]和最小的s[1],操作完再交换回来,所以时间是val×2。
sum是移动所用的时间和,还要减去s[i].val。
s[i]一共移动了cnt-1次,所以是s[i].val*(cnt-1)+sum。

上代码啦

#include<iostream>
#include<cstdio>
#include<algorithm> 
using namespace std;
const int maxn=10007;
int n;
struct cow
{
	int ld,val;
	
}s[maxn];
int vis[maxn];
int cmp(cow a,cow b)//按val排序 
{
	if(a.val==b.val)
	{
		return a.ld<b.ld;
	}
	else return a.val<b.val;
}
int main()
{
    int ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
    	scanf("%d",&s[i].val);
    	s[i].ld=i;
    }
    sort(s+1,s+1+n,cmp);//数组的下标为按val大小排序过的顺序,ld记录原下标 
    int cnt,sum,temp;
    for(int i=1;i<=n;i++)
    {
    	if(vis[i])
    	   continue;
 	    temp=i;
 	    cnt=sum=0;//sum记录需要的时间,cnt记录交换的个数 
 	    while(vis[temp]==0)
 	    {
    	 	sum+=s[temp].val;
    	 	cnt++;
    	 	vis[temp]=1;
    	 	temp=s[temp].ld;
   	    }
   	    sum-=s[i].val;// 
   	    ans+=min(s[i].val*(cnt-1)+sum,s[1].val*(cnt-1)+sum+2*(s[1].val+s[i].val));
    }
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值