计蒜客 - 三值排序

时间限制 1000ms 内存限制 65536K

题目描述

排序是一种很频繁的计算任务。一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌排序的时候。在这个任务中可能的值只有三种123。我们用交换的方法把他排成升序的。

写一个程序计算出,计算出的一个包括123三种值的数字序列,排成升序所需的最少交换次数。

输入第1行为类别的数量N1≤N≤1000

输入第2行到第N+1行,每行包括一个数字(123)。

输出包含一行,为排成升序所需的最少交换次数。

样例输入

9

2

2

1

3

3

3

2

3

1

样例输出

4

 

思路

这道题我是用组合数学的思路来考虑的,首先这个数组里只有3种元素123.假设有a1b2c3,那么最后一定要排成升序,即1 1…1(a)2 2…2(b) 3 3…3(c)这样一个序列,我们就可以把数组的这3段看成是3个不同的盒子,把元素123看成是不同的小球,那么题目就可以转化成下面的问题:123三种球共有n个随机的放在了a,b,c三个不同的盒子里,求通过交换的方式把所有的1球放回a2球放回b3球放回c的最少交换次数。假设初始时aa22球,bb11球,那就让ab之间交换max(a2, b1)次从而使得a中的2球全部放入b中或者b中的1球全部放入1中,因为a2b1不一定相等,所以会使得一些3球在ab之间发生交换,但这是不可避免的。(比如a2=1 b2=3ab交换3个球可以让b的所有1球都到aa中的所有球2b,但是a中还会有23球到b)最后在把c中不是3球的球与ab中的3球交换即可。所以总次数是 max(a2,b1) + c12


#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int n;
int a[1050];

int main() {
	while (scanf("%d", &n) == 1) {
		map<int, int> cnt;
		for (int i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			cnt[a[i]]++;
		}

		int a2 = 0, b1 = 0, c12 = 0, i = 0;
		for (; i < cnt[1]; i++) {
			if (a[i] == 2) a2++;
		}
		for (; i < cnt[1] + cnt[2]; i++) {
			if (a[i] == 1) b1++;
		}
		for (; i < n; i++) {
			if (a[i] == 1 || a[i] == 2) c12++;
		}

		int ans = max(a2, b1) + c12;
		printf("%d\n", ans);
	}
	return 0;
}


posted @ 2017-10-23 23:09  不想吃WA的咸鱼  阅读(130)  评论(0编辑  收藏  举报