Codeforces 134C Swaps (bfs+优先队列)【模板】

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.

Example
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

 【题解】

 大致题意:n个人一起玩游戏,游戏的规则:

1、每次只能交换一张卡片;

2、每个人都不能再获取与手中牌颜色一样的牌;

初始时有可能有人手中没有牌;

要完成这个游戏,需要所有人把自己手中原来的牌在给定的次数中都换出去,如果存在这种换法,则输出yes,并且输出换牌步骤,否则输出no;


解法:

 因为换牌一次是两张,所以s不可能是奇数,,所以如果如果s%2==1,那么一定是不可能的;

 如果出现牌大于总人数的,直接pass;

剩下的就要用bfs搜索了,因为每次只用与最大的那个来换,所以用优先队列保存下来,每次取最大的来换,知道队列为空。

再用个结构体保存每次交换的两张牌的id就好。

下面附上AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<stack>
#include<queue>
using namespace std;
const int N=200000+10;
const int inf=0x3f3f3f3f;
int m,n,a[N];

struct Node
{
    int val;
    int id;

    bool operator < (Node a)const//优先队列
    {
        return val<a.val;
    }
}node[N];

struct no//保存交换的牌id
{
    int x,y;
}ans[N];

int main()
{
    int x;
    Node st,ed;
    priority_queue<Node>q;
    while(~scanf("%d%d",&m,&n))
    {
        int tag=1;
        while(!q.empty()) q.pop();

        for(int i=1;i<=m;++i)
        {
            scanf("%d",&x);
            if(x>=m) tag=0;//如果牌的大小超出了人数  直接pass;
            st.val=x;
            st.id=i;
            if(st.val>0) q.push(st);//满足条件  加入队列
        }
        if(!tag||n%2)//不符合
        {
            printf("No\n");
            continue;
        }
        int cnt=0;
        for(int i=1;;++i)
        {
            if(q.empty()) break;
            st=q.top();
            q.pop();
            //注意这里取出来的st一定是队列中val值最大的;
            if(q.size()<st.val)//队列的中最大的牌的数比总人数还多,直接pass;
            {
                tag=0;
                break;
            }
            for(int j=0;j<st.val;++j)
            {
                ed=q.top();
                q.pop();
                node[j].id=ed.id;
                node[j].val=ed.val;
                node[j].val--;

                ans[cnt].x=st.id;//记录交换前后
                ans[cnt++].y=node[j].id;
            }
            for(int j=0;j<st.val;++j)
                if(node[j].val>0)
                    q.push(node[j]);//还有未交换的  继续加入队列
        }
        if(!tag)
        {
            puts("No");
            continue;
        }
        puts("Yes");
        printf("%d\n",n/2);//交换回合数
        for(int i=0;i<cnt;++i)
            printf("%d %d\n",ans[i].x,ans[i].y);
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值