zoukankan      html  css  js  c++  java
  • POJ 3905 Perfect Election (2-SAT 判断可行)

    题意:有N个人参加选举,有M个条件,每个条件给出:i和j竞选与否会只要满足二者中的一项即可。问有没有方案使M个条件都满足。
    分析:读懂题目即可发现是2-SAT的问题。因为只要每个条件中满足2个中的一个即可,因此将人i拆成 点i表示不竞选,和点i+N表示竞选,根据合取式的满足条件建图跑Tarjan。
    最后检查每个i与i+N是否在同一强连通分量中。

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<stack>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const int maxn =2e3+5;
    const int maxm = 2e6+5;
    struct Edge{
        int v,next;  
    }edges[maxm];
    int head[maxn],tot;
    stack<int> S;
    int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt;
    void init()
    {
        tot = dfn = scc_cnt=0;
        memset(pre,0,sizeof(pre));
        memset(sccno,0,sizeof(sccno));
        memset(head,-1,sizeof(head));
    }
    void AddEdge(int u,int v)   {
        edges[tot] = (Edge){v,head[u]};
        head[u] = tot++;
    }
    void Tarjan(int u)
    {
        int v;
        pre[u]=low[u]=++dfn;
        S.push(u);
        for(int i=head[u];~i;i=edges[i].next){
            v= edges[i].v;
            if(!pre[v]){
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!sccno[v]){
                low[u]=min(low[u],pre[v]);
            }
        }
        if(pre[u]==low[u]){
            int x;
            ++scc_cnt;
            for(;;){
                x = S.top();S.pop();
                sccno[x]=scc_cnt;
                if(x==u)break;
            }
        }    
    }
    
    int N,M;
    
    bool check()
    {
        int all = 2*N;
        for(int i=1;i<=all;++i){
            if(!pre[i]) Tarjan(i);
        }
        for(int i=1;i<=N;i++){
            if(sccno[i]==sccno[i+N]) return false;
        }
        return true;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
        #endif
        while(scanf("%d %d",&N,&M)==2){
            init();
            int x,y,x1,y1,tmp; char c1,c2;
            for(int i=1;i<=M;++i){
                scanf("
    %c%d %c%d",&c1,&x,&c2,&y);
                x1 = x+N,y1 = y+N;      //x1表示x被选
                if(c1=='+' && c2=='+'){
                    AddEdge(y,x1), AddEdge(x,y1);
                }
                else if(c1=='+'){
                    AddEdge(x,y), AddEdge(y1,x1);
                }
                else if(c2=='+'){
                    AddEdge(x1,y1), AddEdge(y,x);
                }
                else{
                    AddEdge(x1,y), AddEdge(y1,x);
                }
            }
            if(check()) puts("1");
            else puts("0");
        }
        return 0;
    }
    
    为了更好的明天
  • 相关阅读:
    1002CSP-S模拟测试赛后总结
    「题解」:X国的军队
    1001CSP-S模拟测试赛后总结
    「题解」:联
    0929CSP-S模拟测试赛后总结
    「题解」:Kill
    「题解」:y
    Censoring【自动AC机】【水题毁我青春】【20190614】
    传说级快读
    针对值域与下标关系的总结
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9560620.html
Copyright © 2011-2022 走看看