HDU 1824 —— Let's go home(2-SAT)

来源:互联网 发布:淘宝网上手机 编辑:程序博客网 时间:2024/05/21 06:24

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

第一次写2-SAT,纪念一下。

根据题目的描述,大概分为几种情况:

同一队伍的三个人A,B,C产生的限制是:A回去=>B留下,A回去=>C留下,B回去=>A留下,C回去=>A留下

一对人A和B的限制是:A留下=>B回去,B留下=>A回去

按照上面的方法建立有向图,然后进行强联通分量的缩点,如果存在某个X,使得X回去和X留下存在同一个强连通分量,则说明有矛盾,无法满足。

如果找不到冲突,那就是yes了。

#include<cstdio>#include<cstring>#include<vector>#include<algorithm>#include<stack>using namespace std;#define N 6000#define pb push_backvector<int> V[N];int t, n, m;int pre[N], low[N], sccno[N], dfs_clock, scc_cnt;stack<int> S;void dfs(int x){    pre[x] = low[x] = ++dfs_clock;    S.push(x);    for(int i=0; i<V[x].size(); i++){        int j=V[x][i];        if(!pre[j]){            dfs(j);            low[x] = min(low[x],low[j]);        }        else if(!sccno[j]){            low[x] = min(low[x],pre[j]);        }    }    if(low[x]==pre[x]){        scc_cnt++;        for(;;){            int u=S.top();S.pop();            sccno[u]=scc_cnt;            if(x==u)    break;        }    }}void find_scc(){    dfs_clock = scc_cnt = 0;    memset(sccno, 0, sizeof(sccno));    memset(pre, 0, sizeof(pre));    for(int i=0; i<2*n; i++){        if(!pre[i]) dfs(i);    }}void add(int x,int y){    V[x].pb(y);}bool solve(){    find_scc();    for(int i=0; i<n; i++){        if(sccno[i]==sccno[i+n])    return 0;    }    return 1;}int main(){    while(~scanf("%d %d", &t, &m)){        n = t*3;        for(int i=0; i<2*n; i++)  V[i].clear();        int x, y, z;        for(int i=0; i<t; i++){            scanf("%d %d %d", &x, &y, &z);            add(y+n, x);            add(z+n, x);            add(x+n, y);            add(x+n, z);        }        while(m--){            scanf("%d %d", &x, &y);            add(x, y+n);            add(y, x+n);        }        puts(solve()?"yes":"no");    }    return 0;}


0 0
原创粉丝点击