hdu5971/2016icpc大连 Wrestling Match

7 篇文章 0 订阅
2 篇文章 0 订阅

Wrestling Match

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2616    Accepted Submission(s): 964


Problem Description
Nowadays, at least one wrestling match is held every year in our country. There are a lot of people in the game is "good player”, the rest is "bad player”. Now, Xiao Ming is referee of the wrestling match and he has a list of the matches in his hand. At the same time, he knows some people are good players,some are bad players. He believes that every game is a battle between the good and the bad player. Now he wants to know whether all the people can be divided into "good player" and "bad player".
 

Input
Input contains multiple sets of data.For each set of data,there are four numbers in the first line:N (1 ≤ N≤ 1000)、M(1 ≤M ≤ 10000)、X,Y(X+Y≤N ),in order to show the number of players(numbered 1toN ),the number of matches,the number of known "good players" and the number of known "bad players".In the next M lines,Each line has two numbersa, b(a≠b) ,said there is a game between a and b .The next line has X different numbers.Each number is known as a "good player" number.The last line contains Y different numbers.Each number represents a known "bad player" number.Data guarantees there will not be a player number is a good player and also a bad player.
 

Output
If all the people can be divided into "good players" and "bad players”, output "YES", otherwise output "NO".
 

Sample Input
 
 
5 4 0 01 31 43 54 55 4 1 01 31 43 54 52
 
Sample Output
 
 
NOYES
 

Source
2016ACM/ICPC亚洲区大连站-重现赛(感谢大连海事大学)

题目大意:

有n个玩家,m场比赛,其中有x个人是good,y个人是bad,每一场比赛都看做是一个good和一个bad的比赛,问是否所有人都能分成good和bad。

题目分析:

其实这题我一直有个疑问,就是关于“不确定”的情况,如果是一个正方形ABCD,那么按测试用例就是可以分的,但按我的理解,只能确定AC和BD分为两组,但谁是good谁是bad并不知道。不过既然测试用例是这样的,也经历了若干发wa,这题应该只能这么理解:

首先这个图有可能是断的,那么如果有1个点的分量,若它是不知道的,那就不能确定,否则,则看这个分量在部分点已经确定颜色的情况下能否二分染色即可


实际上这个题,并查集的用处在于把点连在一起,和得到染色的起点,以及判断单块的并查集里有没有已经染色的点



ac代码:

#include<bits/stdc++.h>

using namespace std;

int n,m,x,y;
bool vis[1005];//记录数组
int fa[1005];//并查集
int c[1005];//记录颜色
int link[1005];//如果某块并查集里有含有颜色的点,把根节点指向它,确定根节点开始染色时的颜色
int num[1005];//记录某一块有多少个点,如果根节点为1,则为单点,用来特判
vector<int>G[1005];//用来保存相邻的关系,可以看为邻接矩阵

int fin(int x)
{
    return fa[x]==x?x:fin(fa[x]);
}

void unio(int i,int j)
{
    i = fin(i);
    j = fin(j);
    if(i != j)
    {
        fa[i] = j;
        num[j] += num[i];
    }
}
//dfs染色
bool dfs(int po,int col)
{
    c[po] = col;
    vis[po] = true;

    for(int i = 0; i < G[po].size(); i++)
    {
        int v = G[po][i];
        if(c[v] == col)//相邻的点颜色必须不同,不然无法判断好坏
            return false;
        else if(!vis[v])
        {
            if(col == 1)
            {
                if(!dfs(v,2))
                    return false;
            }
            else
            {
                if(!dfs(v,1))
                    return false;
            }
        }
    }

    return true;
}

int main()
{

    while(~scanf("%d %d %d %d",&n,&m,&x,&y))
    {
        memset(c,0,sizeof(c));
        memset(vis,false,sizeof(vis));
        for(int i = 1; i <= n; i++)
        {
            fa[i] = i;
            link[i] = 0;
            G[i].clear();
            num[i] = 1;
        }

        int cr,cl;

        for(int i = 0; i < m; i++)
        {
            scanf("%d %d",&cr,&cl);
            G[cr].push_back(cl);
            G[cl].push_back(cr);
            unio(cr,cl);
        }

        for(int i = 0; i < x; i++)
        {
            scanf("%d",&cr);
            c[cr] = 1;
            link[fin(cr)] = cr;
        }

        for(int i = 0; i < y; i++)
        {
            scanf("%d",&cl);
            c[cl] = 2;
            link[fin(cl)] = cl;
        }

        bool dis = true;

        if(n == 1 && c[1] == 0)//特判
            dis = false;

        for(int i = 1; i <= n; i++)
        {
            if(num[fin(i)] == 1 && c[i] == 0)//单点无颜色
            {
                dis = false;
                break;
            }
        }

        if(dis)
        {
            for(int i = 1; i <= n; i++)
            {
                int p = fin(i);
                if(link[p] == 0)//这一块全是空白的点
                    dis = dfs(p,1);
                else
                    dis = dfs(link[p],c[link[p]]);//不是空白,从有颜色的点开始向四周染色

                if(!dis)
                    break;
            }
        }

        if(dis)
            printf("YES\n");
        else
            printf("NO\n");

    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值