CodeForces 370C Mittens

题意:

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值