2016 ACM/ICPC大连区域赛 A— Wrestling Match【2-sat】

http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1001&cid=736

Wrestling Match

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

 

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

题意:

n个人,m场比赛,每一场比赛必有一个好的,一个坏的。

如果存在一个人既是好的又是坏的,那么输出NO【一定注意大写】

如果比赛中没有出现,并且也没有提示是好的坏的,那么输出NO【一定注意大写】

否则YES

分析:

这个题其实就是暴力深搜,也算是2-sat的思想,我直接套的模板,但是没有注意输出格式,wrong了好多发。

代码:

#include<bits/stdc++.h>

using namespace std;
const int maxn=10000+10;
bool vis[maxn*2];
struct TwoSAT
{
    int n;//原始图的节点数(未翻倍)
    vector<int> G[maxn*2];//G[i]==j表示如果mark[i]=true,那么mark[j]也要=true
    bool mark[maxn*2];//标记
    int S[maxn*2],c;//S和c用来记录一次dfs遍历的所有节点编号

    void init(int n)
    {
        this->n=n;
        for(int i=0;i<2*n;i++) G[i].clear();
        memset(mark,0,sizeof(mark));
    }

    //加入(x,xval)(y,yval)中有一个是对的,另一个不对
    //xval=0表示假,yval=1表示真
    void add_clause(int x,int xval,int y,int yval)
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }

    //从x执行dfs遍历,途径的所有点都标记
    //如果不能标记,那么返回false
    bool dfs(int x)
    {
        if(mark[x^1]) return false;//这两句的位置不能调换
        if(mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        for(int i=0;i<G[x].size();i++)
            if(!dfs(G[x][i])) return false;
        return true;
    }

    //判断当前2-SAT问题是否有解
    bool solve()
    {
        for(int i=0;i<2*n;i+=2)
        if(!mark[i] && !mark[i+1])
        {
            c=0;
            if(!dfs(i))
            {
                while(c>0) mark[S[--c]]=false;
                if(!dfs(i+1)) return false;
            }
        }
        return true;
    }
}fun;

int main()
{
    int i,j,x,y,aa,bb,m,n;
    while(~scanf("%d%d%d%d",&n,&m,&x,&y))
    {
        fun.init(n);
        memset(vis,0,sizeof(vis));
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&aa,&bb);
            aa--;
            bb--;
            fun.add_clause(aa,1,bb,1);
            fun.add_clause(aa,0,bb,0);
            vis[aa]=1;
            vis[bb]=1;

        }
        for(i=0;i<x;i++)
        {
            scanf("%d",&aa);
            aa--;
            vis[aa]=1;
            fun.add_clause(aa,1,aa,1);
        }
        for(i=0;i<y;i++)
        {
            scanf("%d",&aa);
            aa--;
            vis[aa]=1;
            fun.add_clause(aa,0,aa,0);
        }
        bool flag;
        flag=-1;

        for(i=0;i<n;i++)
        {
            if(vis[i]==0)
            {
                flag=0;
                break;
            }
        }
        if(flag==0)
        {
            printf("NO\n");
            continue;
        }
        flag=fun.solve();
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");

    }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值