Codeforces 134C - Swaps(优先队列)

There are n players sitting at a round table. All of them have s cards of n colors in total. Besides, initially the first person had cards of only the first color, the second one had cards of only the second color and so on. They can swap the cards by the following rules:

as the players swap, a player can give a card of his color only;
a player can’t accept a card of a color he already has (particularly, he can’t take cards of his color, no matter whether he has given out all of them or not);
during one swap a pair of people swaps cards (each person gives one card and takes one card).
The aim of all n people is as follows: each of them should give out all the cards he had initially (that is, all cards of his color). Your task is to denote whether such sequence of swaps is possible. If the answer is positive, you should list all the swaps.

Input
The first line contains integers n (1 ≤ n ≤ 200000) and s (1 ≤ s ≤ 200000). The second line contains n numbers, the i-th number stands for how many cards the i-th player has by the moment the game starts. It is possible that a player has no cards initially.

Output
On the first line print “No” if such sequence of swaps is impossible. Otherwise, print “Yes”. If the answer is positive, next print number k — the number of the swaps. Then on k lines describe the swaps by pairs of indices of the swapping players. Print the swaps and the numbers of the swaps in any order.

Examples
Input
4 8
2 2 2 2
Output
Yes
4
4 3
4 2
1 3
1 2
Input
6 12
1 1 2 2 3 3
Output
Yes
6
6 5
6 4
6 3
5 4
5 3
2 1
Input
5 5
0 0 0 0 5
Output
No

题目链接
参考题解
1、每次只能交换一张卡片;
2、每个人都不能再获取与手中牌颜色一样的牌;
初始时有可能有人手中没有牌;
要完成这个游戏,需要所有人把自己手中原来的牌在给定的次数中都换出去,如果存在这种换法,则输出yes,并且输出换牌步骤,否则输出no;

1、首先,卡牌的总数量一定是偶数,因为每一次交换都是两张牌,而且又不能拿到自己原来的牌,所以牌的数量一定是偶数,只要是奇数张那就直接不用后续操作了。
2、如果有人手中的卡牌数量大于总人数了,那么也一定是不可行的,因为人数太少,每个人拿到这张牌之后就不可以再拿了,那么手里一定剩下一部分牌是发不出去的。

然后不可能的情况排除以后,就开始模拟一下,从牌最多的那个人开始,每次都发给牌比较多的那些人进行交换,用优先队列,然后结构体保存一下交换时候的步骤就可以了。
AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 2e5 + 5;

struct node //记录每个人的id和手中的牌数量
{
    int id, val;
    node(int id = 0, int val = 0) : id(id), val(val){};
    bool operator < (const node& obj) const
    {
        return val < obj.val;
    }
}person[maxn];

struct card_swap    //记录卡牌交换
{
    int card_a, card_b;
}card_ans[maxn];

int main()
{
    int num_kind, num_card, num_one;
    while(~scanf("%d%d", &num_kind, &num_card))
    {
        bool flag = true; //保证每一个人手中的牌都小于总人数,如果大于总人数,那么一定没法换完
        priority_queue<node> q;
        for(int i = 1; i <= num_kind; i++)
        {
            scanf("%d", &num_one);
            if(num_one > num_kind)  flag = false;   //如果已经比人数多了,那么一定无法完成交换
            if(num_one) q.push(node(i, num_one));
        }

        if(!flag || num_card & 1)   //牌的数量只能为奇数,因为一次交换就是两张牌
        {
            printf("No\n");
            continue ;
        }
        int step = 0;
        while(q.size())
        {
            node per_1, per_2;
            per_1 = q.top();
            q.pop();

            if(per_1.val > q.size())    //如果是卡牌数量大于当前队列中的人数,那么也无法完成交换,退出
            {
                flag = false;
                break ;
            }
            for(int i = 0; i < per_1.val; i++)  //遍历当前点的每一次遍历
            {
                per_2 = q.top();
                q.pop();
                //将与之交换的点都记录下来
                person[i].id = per_2.id;
                person[i].val = per_2.val - 1;
                //记录答案,即交换的过程
                card_ans[step].card_a = per_1.id;
                card_ans[step++].card_b = per_2.id;
            }
            for(int i = 0; i < per_1.val; i++)
                if(person[i].val)
                    q.push(person[i]);
        }
        if(!flag)
        {
            printf("No\n");
            continue ;
        }
        printf("Yes\n%d\n", step);
        for(int i = 0; i < step; i++)
            printf("%d %d\n", card_ans[i].card_a, card_ans[i].card_b);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40788897/article/details/83060046
今日推荐