HDU 5971 Wrestling Match(dfs)

                                                 Wrestling Match

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


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 0 1 3 1 4 3 5 4 5 5 4 1 0 1 3 1 4 3 5 4 5 2
 

Sample Output
   
   
NO YES
 

Source


题意:

    大概意思是有n个编号为1~n的人,每个人应该都有一个“好”或“坏”的属性,并且题上已知有m对“好坏”的组队,在这m对里每一对有2个人,并且这2个人一定有一个是“好”人,另外一个是“坏”人,但是并不知道他们到底谁是”好”或”坏”。而且会告诉你有x个编号已知的“好”人,也有y个编号已知的“坏”人。现在告诉你这些条件,让你判断这n个人是否能全部分清“好”或“坏”的属性。

    在样例1中:1和4,1和3,3和5,4和5,0个已知好人和0个已知坏人,所以我们可以假设1是好人,则3,4是坏人,推理5号是好人,没有冲突,所以,1,3,4,5,是可以确定的。2号无论为坏人或好人都可以,所以2号未知。则2号无法满足题目要求,所以是NO

而在样例2中,多了一个已知2号是好人的条件,所以1~5号都已知,满足题目要求,所以是YES。


    这道题的解题思路就是用链式前向星储存m组相连的人,再在已知的好人和坏人中判断与之有联系的人的属性,如果有冲突,比如1和3,1和2,2和3,其中2和3就有冲突,这种情况用一个标记好坏属性的数组来处理,如果已知1是好人,标记a[1]=1,则与之相连的2和3就是坏人,则标记a[2]=a[3]=0,再继续找2和3相连的,如果发现相连的有冲突,则确定有冲突,直接返回NO。如果遍历完相连的每个点。发现都符合,则表示这几组都正常。

    当判断完题目已知的好人和坏人时,再遍历一下看谁的属性还未确定,如果发现这个人是个独点,直接判断NO。如果不是独点的话,重复上面的判断过程,在判断的时候可以随意给起始的搜索点一个状态,然后搜索判断。其中判断的过程我是用DFS写的。

PS:一定,一定,一定要注意清空。(我因为没有清空数组,结果一直WA)/(ㄒoㄒ)/~~。。。。但是!!但是!!神奇的是即使不清空vector,我在搜索的时候加了个判断搜索点是否大于N,如果大于则直接返回。结果神奇的AC了。真有毒~~~



#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <queue>
#include <vector>
#define inf 0x6fffffff
#define LL long long
#define mem(p,k) memset(p,k,sizeof(p));
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int f[2010],g[2010],h[2010][2010],num[2010],n;
vector<int>a[1010];

int dfs(int x){
    for(int i=0;i<a[x].size();i++){
//        if(a[x][i]>n){
//            continue;
//        }
        //cout<<x<<"="<<a[x][i]<<endl;
        if(g[a[x][i]]==-1){
            g[a[x][i]]=g[x]^1;
            //cout<<a[x][i]<<"="<<g[a[x][i]]<<en
        }
        else {
            if(g[x]==g[a[x][i]])return 0;
        }
        if(!h[x][a[x][i]]){
                h[x][a[x][i]]=1;
                h[a[x][i]][x]=1;
                if(dfs(a[x][i])==0){
                    return 0;
                }
        }
    }
    return 1;

}
int main()
{
    int m,x,y,k,cur;
    while(~scanf("%d%d%d%d",&n,&m,&x,&y)){
        for(int i=0;i<1010;i++){
            a[i].clear();
        }
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=0;i<m;i++){
            int x1,x2;
            scanf("%d%d",&x1,&x2);
            a[x1].push_back(x2);
            a[x2].push_back(x1);
        }
        mem(g,-1);
        mem(h,0);
        mem(num,0);
        k=0;
        cur=1;
        for(int i=0;i<x;i++){
            scanf("%d",num+k);
            g[num[k]]=1;
            k++;
        }
        for(int i=0;i<y;i++){
            scanf("%d",num+k);
            if(g[num[k]]!=-1){
                cur=0;
            }
            g[num[k]]=0;
            k++;
        }
        if(!cur){
            cout<<"NO"<<endl;continue;
        }
        cur=1;

        for(int i=0;i<k;i++){
               if(dfs(num[i])==0){
                cout<<"NO"<<endl;
                cur=0;
                break;
               }
        }

        if(!cur)continue;

        cur=1;
        for(int i=1;i<=n;i++){
            if(g[i]==-1){
              //  cout<<i<<endl;
                g[i]=1;
                if(a[i].empty()||!dfs(i)){
                        cout<<"NO"<<endl;
//                         for(int i=1;i<=n;i++){
//                    cout<<i<<"="<<g[i]<<endl;
//                }
                        cur=0;break;
                }

            }
        }
        if(cur)cout<<"YES"<<endl;
    }

    return 0;
}

 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值