题意:
n个人 每人有一副手套(左右手同样颜色) 现在他们可以随便找人交换手套(左手只能换左手) 问 最多几个人所带的手套是不同色的 输出任意一种方案
思路:
一开始以为是二分图问题 无奈n太大了 TLE
这题其实是想法题 设 num[i] 为带i颜色的手套的人数 mx 为最大的num所对的i
如果 n-num[mx]<=num[mx] 那么最优方案一定是所有颜色非mx的人和颜色是mx的人换一只手套 最后剩下一些人这些人一定是带mx颜色的
如果 n-num[mx]>num[mx] 一定可以让n个人都满足条件 理由如下
按num排序 然后i从前到后遍历j从后到前遍历 如果i和j手套颜色不同就交换 直到剩下一些人
这些人手套颜色一定不是mx(因为num[mx]个数不过半 就是如果中写的) 那么我可以让这些人和等量队列前面的人换另一只手套(注意不要交换刚才换的手套) 这时一定不会出现手套颜色相同的人(因为如果出现说明剩下的颜色的num比mx的num要大 不满足mx的定义)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int num[110],ansx[5010],ansy[5010];
int n,m,top,mx;
struct fzc
{
int col,num;
bool operator<(const fzc fa) const
{
return num<fa.num;
}
}nd[110];
int main()
{
int i,j,tmp;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&j);
num[j]++;
if(num[j]>num[mx]) mx=j;
}
if(num[mx]*2>=n)
{
printf("%d\n",(n-num[mx])*2);
for(i=1;i<=m;i++)
{
if(i==mx) continue;
for(j=1;j<=num[i];j++)
{
printf("%d %d\n",i,mx);
printf("%d %d\n",mx,i);
num[mx]--;
}
}
for(i=1;i<=num[mx];i++) printf("%d %d\n",mx,mx);
}
else
{
printf("%d\n",n);
for(i=1;i<=m;i++)
{
if(num[i])
{
nd[top].col=i;
nd[top].num=num[i];
top++;
}
}
sort(nd,nd+top);
for(i=0,j=1;i<top;i++)
{
tmp=nd[i].num;
while(tmp--)
{
ansx[j]=ansy[j]=nd[i].col;
j++;
}
}
for(i=1,j=n;ansy[i]!=ansy[j]&&i<=n/2;i++,j--)
{
swap(ansy[i],ansy[j]);
//printf("%d %d %d %d %d %d \n",i,ansx[i],ansy[i],j,ansx[j],ansy[j]);
}
tmp=j;
for(j=1;i<=tmp;i++,j++) swap(ansx[i],ansx[j]);
for(i=1;i<=n;i++) printf("%d %d\n",ansx[i],ansy[i]);
}
return 0;
}