hdu 1824-Let's go home 2-SAT (模板)

57 篇文章 0 订阅
15 篇文章 0 订阅

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1824

 

Let's go home

Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2588    Accepted Submission(s): 1125


 

Problem Description

小时候,乡愁是一枚小小的邮票,我在这头,母亲在那头。
                        —— 余光中

集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。

 

 

Input

第一行有两个整数,T和M,1<=T<=1000表示队伍数,1<=M<=5000表示对数。
接下来有T行,每行三个整数,表示一个队的队员编号,第一个队员就是该队队长。
然后有M行,每行两个整数,表示一对队员的编号。
每个队员只属于一个队。队员编号从0开始。

 

 

Output

可行输出yes,否则输出no,以EOF为结束。

 

 

Sample Input

 

1 2 0 1 2 0 1 1 2 2 4 0 1 2 3 4 5 0 3 0 4 1 3 1 4

 

 

Sample Output

 

yes no

 

 

Author

威士忌

 

 

Source

HDOJ 2007 Summer Exercise(3)- Hold by Wiskey

 

 

Recommend

威士忌   |   We have carefully selected several similar problems for you:  1823 1826 1827 1822 1825 

 

 

Statistic | Submit | Discuss | Note

 

题意: 

        集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。

分析:

        其实就是简单的2-SAT问题判断,每个人有两种选择:留=0或走=1.

  • 然后该2-SAT要满足两类条件,第一类是 队长留 or 另外两个队员留.

  • 第二类是由M指出的 一对队员a和b的冲突条件.

        假设a b c 组成一个队,且a是队长,那么由于队长a与队员(b,c)组合二者只能选其一,

TS.add_and_clause(b,0,c,0);//b留c留
TS.add_and_clause(c,0,b,0);//c留b留

TS.add_and_clause(a,1,b,0);//a走b留

TS.add_and_clause(a,1,c,0);//a走c留

TS.add_and_clause(b,1,a,0);//b走a留

TS.add_and_clause(c,1,a,0);//c走a留

      对于另外M个条件的a与b来说有:

 

TS.add_and_clause(a,0,b,1);//a留,导致b走
TS.add_and_clause(b,0,a,1);//b留,导致a走

 //注意用的是AND

这样错了好几次

This is the code:

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define pppp cout<<endl;
#define EPS 1e-8
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x3f3f3f3f      //1061109567
#define LL_INF 0x3f3f3f3f3f3f3f3f //4557430888798830399
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
const int dr[]= {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]= {-1, 1, 0, 0, -1, 1, -1, 1};
int read()//输入外挂
{
    int ret=0, flag=0;
    char ch;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        ret = ch - '0';
    while((ch=getchar())>='0'&&ch<='9')
        ret=ret*10+(ch-'0');
    return flag ? -ret : ret;
}

const int maxn= 100000+10;
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_or_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,xval)且(y,yval)条件
    //xval=0表示假,yval=1表示真
    void add_and_clause(int x,int xval,int y,int yval)//表示或的意思
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x].push_back(y);
    }

    //从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;
    }
} TS;


int main()
{
    //freopen("D:\\chnegxubianji\\inORout\\in.txt", "r", stdin);
    //freopen("D:\\chnegxubianji\\inORout\\out.txt", "w", stdout);
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        TS.init(n*3);
        while(n--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);

            TS.add_and_clause(b,0,c,0);//b留c留
            TS.add_and_clause(c,0,b,0);//c留b留

            TS.add_and_clause(a,1,b,0);//a走b留
            //TS.add_and_clause(b,0,a,1);//b留a走

            TS.add_and_clause(a,1,c,0);//a走c留
            //TS.add_and_clause(c,0,a,1);//c留a走

            TS.add_and_clause(b,1,a,0);//b走a留
            //TS.add_and_clause(a,0,b,1);//a留b走

            TS.add_and_clause(c,1,a,0);//c走a留
            //TS.add_and_clause(a,0,c,1);//a留c走


            //TS.add_and_clause(b,1,c,1);//b走c走
            //TS.add_and_clause(c,1,b,1);//c走b走

        }

        while(m--)
        {
            int a,b;
            scanf("%d%d",&a,&b);

            TS.add_and_clause(a,0,b,1);//a留,导致b走
            TS.add_and_clause(b,0,a,1);//b留,导致a走

        }
        bool flag=TS.solve();
        if(flag)
            puts("yes");
        else
            puts("no");
    }
    return 0;
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值