usaco2.1.3-----Sorting a Three-Valued Sequence(*三值交换排序)

/*
ID:lvfuan11
PROG:sort3
LANG:C++

translation:
	有1,2,3三个数字组成的数列,现在要将其变成有序数列,求最少要交换多少次。
solution:
	首先定义两个数字如果交换后都在正确的位置上,那么称这两个数字为交叉相等。所以根据贪心的思路很容易想到交叉相等的
	数字肯定要交换。这样将所有交叉相等的数字处理完后就完成了算法的第一步。
	那么如何处理剩下的数字?这里有个规律,就是剩下的数字肯定是3的倍数(证明见note),且两两不交叉相等。意味着只要
	以3个数字为1组,一一处理即可。一组三个数字需要交换2次。统计出来这次的交换次数,加上第一步的交换次数就是答案。
note:
	* 为什么说剩下的数字个数肯定是3的倍数?
	  首先定义p(i,j)=k的意义为,某位置上原本出现数字i,现在却出现数字j的位置有k个。则有一个推论:p(2,1)>0和
	  p(2,3)>0不会同时存在(p(1,2)和p(1,3), p(3,1)和p(3,2)同理)。因为假如两个都同时大于0,则1的位置上只能有
	  3,因为经过第一步后p(1,2)和p(2,1)相互抵消,p(2,1)>0则p(1,2)肯定已经为0!同理3的位置上也只能出现1。那么就有
	  p(3,1)>0 且 p(1,3)>0同时存在,那么就可以继续执行第一步,相互矛盾。故推论成立!
	  证明推论之后就简单了,假设有:
	  p(2,1)=x0;
	  p(2,3)=x1;
	  p(1,2)=x2;
	  p(1,3)=x3;
	  p(3,2)=x4;
	  p(3,1)=x5;
	  则根据上述推论,若x0不为0,那么x1=x2=0,若x4不等0,则x5肯定为0.那么剩下的数字个数为x0+x3+x4,可以发现这三个数肯定相等
	  ,因为若不等的话,那么结果无论怎么交换都无法交换到正确的顺序上。得证
*/
#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>

using namespace std;
const int maxn = 1000 + 5;

int a[maxn], b[maxn], n;
set<int> rightPos[4];

inline bool inPos(int x, int p)
{
	if(rightPos[x].find(p) != rightPos[x].end())	return true;
	else	return false;
}

int main()
{
	freopen("sort3.in", "r", stdin);
	freopen("sort3.out", "w", stdout);
    while(~scanf("%d", &n)) {
		for(int i = 1; i <= 4; i++) rightPos[i].clear();

		for(int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
			b[i] = a[i];
		}

		sort(b + 1, b + n + 1);

		for(int i = 1; i <= n; i++) {
			rightPos[b[i]].insert(i);
		}

		int ans = 0;
		for(int i = 1; i <= n; i++) {
			if(inPos(a[i], i))	continue;
			for(int j = 1; j <= n; j++) if(i != j) {
				if(inPos(a[i], j) && inPos(a[j], i)) {
					swap(a[i], a[j]);
					ans++;
					break;
				}
			}
		}

		int res = 0;
		for(int i = 1; i <= n; i++)
			if(a[i] != b[i])	res++;
		printf("%d\n", ans + res / 3 * 2);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值