这道题目我一开始想错了,觉得只要排好序,再从头到尾把可以相互交换的进行下交换就可以了。。。事实证明是错的。正确的解法比较巧妙,而且写法非常好,值得学习
首先,要注意的一个规律是,假如最大的颜色数字出现的次数 为 c, c超过了n的一半,则必定无法将所有的人的颜色交换成两两不同的,而且此时颜色不同的人的数目也已经出来了
就是 (n-c)*2,于此,也很容易得出,一旦c没有超过n的一半,则肯定能够把所有人都排成不一样的,(先把相同颜色的找另一类相同颜色的互换,某一类不够了,再找另一类的来继续补充一下即可)此时的答案就是n。
进一步分析,如果是第一种情况,则一个很巧妙的处理方法就是从1到n遍历,如果当前i的颜色为颜色最多的那个颜色,则,先输出i颜色,再从非c颜色里面找不同的来匹配,当然最多只能找d个,d=n-c,如果找完d个了,就只能输出一样的颜色了,代表该人无法颜色不同。。。如果当前颜色不为i那个颜色,则先输出该颜色,再输出那个最多的颜色。
第二种情况的话,先对颜色进行排序,把相同颜色的放在一起,然后有个很巧妙的处理方法,就是某颜色的另一半=(i+c)%n.color,这个好好想想就能明白,既能遍历完整个n,又能保证不会遇到重复色(因为相同颜色在同一堆,而且这一堆的数目最大为c,所以+c再对n取模,是绝对不会匹配大到相同的颜色的)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct node {int date;int id;int other; } p[5005]; bool cmp(node a,node b) {return a.date<b.date; } bool cmp2(node a,node b) {return a.id<b.id; } int c[105]; int main() {int n,m,i,j;while (scanf("%d%d",&n,&m)!=EOF){memset(c,0,sizeof c);for (i=1;i<=n;i++){scanf("%d",&p[i].date);p[i].id=i;c[p[i].date]++;}int maxn=0,index;for (i=1;i<=m;i++){if (maxn<c[i]){maxn=c[i];index=i;}}if (maxn*2>n){printf("%d\n",(n-maxn)*2);int d=n-maxn;j=0;for (i=1;i<=n;i++){if (p[i].date==index){printf("%d ",index);if (d>0){for (j++;j<=n && p[j].date==index;j++); //这里是个细节,j每次先要++printf("%d\n",p[j].date);d--;}elseprintf("%d\n",index);}else{printf("%d %d\n",p[i].date,index);}}}else{printf("%d\n",n);sort(p+1,p+1+n,cmp);for (i=1;i<=n;i++){int loc=i+maxn;loc%=n;if (loc==0) loc=n;p[i].other=p[loc].date;}sort(p+1,p+1+n,cmp2);for (i=1;i<=n;i++){printf("%d %d\n",p[i].date,p[i].other);}}}return 0;}