zoukankan      html  css  js  c++  java
  • 2-sat

    模板

    void addedge(int u,int v){
    	g[u].pb(v);
    	rg[v].pb(u);
    }
    void dfs(int u){
    	vis[u]=1;
    	for(int i=0;i<g[u].size();i++)
    		if(!vis[g[u][i]])
    			dfs(g[u][i]);
    	cb.pb(u);
    }
    void rdfs(int u,int k){
    	vis[u]=1;
    	cmp[u]=k;
    	for(int i=0;i<rg[u].size();i++)
    		if(!vis[rg[u][i]])
    			rdfs(rg[u][i],k);
    }
    int n,m;
    int scc(){///返回强连通分量的数量
    	for(int i=0;i<2*n;i++)
    		if(!vis[i])
    			dfs(i);
    	int k=0;
    	memset(vis,0,sizeof(vis));
    	for(int i=cb.size()-1;i>=0;i--){
    		if(!vis[cb[i]])
    			rdfs(cb[i],k++);
    	}
    	return k;
    }
    

      

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

    题目思路:

                     对于这类问题一般的解法为将每个点分为 x 和 x' 分别表示每组当中的两种状态,这里表示丈夫和妻子,然后更具定义我们建图,如果 A和B有矛盾则选A必选B',选B必选A' ,所以我们对该图缩点,如果A和A'属于同一个环当中则说明选A必选A',所以不存在,否则就存在

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    #define pb push_back
    const int M=5000;
    vector<int>g[M];
    int low[M],dfn[M],sta[M],vis[M],cmp[M];
    int tot,cnt,top;
    void tarjan(int u){
        low[u]=dfn[u]=++cnt;
        sta[++top]=u;
        vis[u]=1;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u]){
            tot++;
            cmp[u]=tot;
            vis[u]=0;
            while(sta[top]!=u){
                cmp[sta[top]]=tot;
                vis[sta[top--]]=0;
            }
            top--;
        }
    }
    int main(){
        int n,m;
        while(~scanf("%d%d",&n,&m)){
            for(int i=0;i<=2*n;i++)
                g[i].clear(),low[i]=dfn[i]=cmp[i]=vis[i]=sta[i]=0;
            top=cnt=tot=0;
            while(m--){
                int a1,a2,c1,c2;
                scanf("%d%d%d%d",&a1,&a2,&c1,&c2);
                int a = a1*2+c1;
                int b = a2*2+c2;
                g[a].pb(b^1);
           //     cout<<u<<"----"<<2*a2+(1-c2)<<endl;
          //      g[2*a2+(1-c2)].pb(u);
                g[b].pb(a^1);
           //     cout<<v<<"----"<<2*a1+(1-c1)<<endl;
          //      g[2*a1+(1-c1)].pb(v);
            }
            for(int i=0;i<2*n;i++)
                if(!dfn[i])
                    tarjan(i);
            int flag=1;
            for(int i=0;i<n;i++){
                if(cmp[2*i]==cmp[2*i+1]){
                    flag=0;
                    break;
                }
    
            }
            if(flag)
                puts("YES");
            else
                puts("NO");
    
        }
    
        return 0;
    }
    View Code

     例题:输出满足条件的方案是什么

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

    把所有能到达的点标记一下,顺便判断一下和之前有没有矛盾,有矛盾的话所有被标记的点又要重新标记回去。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define pb push_back
    const int M=2e4+4;
    vector<int>g[M];
    int vis[M],s[M],tot,n;
    bool dfs(int u){
        if(vis[u])
            return true;
        if(vis[u^1])
            return false;
        vis[u]=1;
        s[tot++]=u;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!dfs(v))
                return false;
        }
        return true;
    }
    bool solve(){
        for(int i=0;i<2*n;i+=2){
            if(vis[i]||vis[i^1])
                continue;
            tot=0;///相当于缩点过程 
            if(!dfs(i)){
                while(tot)
                    vis[s[--tot]]=0;
                if(!dfs(i^1))
                    return false;
            }
        }
        return true;
    }
    int main(){
        int m;
        while(~scanf("%d%d",&n,&m)){
            for(int i=0;i<=2*n;i++)
                g[i].clear(),vis[i]=0;
            while(m--){
                int u,v;
                scanf("%d%d",&u,&v);
                u--,v--;
                g[u].pb(v^1);
                g[v].pb(u^1);
            }
            if(solve()){
                for(int i=0;i<2*n;i++)
                    if(vis[i])
                        printf("%d
    ",i+1);
            }
            else
                puts("NIE");
        }
        
        return 0;
    }
    View Code

     题:https://codeforces.com/problemset/problem/468/B

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    const int M=2e5+5;
    struct node{
        int val,id;
        bool operator<(const node &b)const{
            return val<b.val;
        }
    }a[M];
    vector<int>g[M],rg[M],newg;
    int vis[M],cmp[M];
    void addedge(int u,int v){
        g[u].pb(v);
        rg[v].pb(u);
    }
    void dfs(int u){
        vis[u]=1;
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(!vis[v])
                dfs(v);
        }
        newg.pb(u);
    }
    void rdfs(int u,int k){
        vis[u]=1;
        cmp[u]=k;
        for(int i=0;i<rg[u].size();i++){
            int v=rg[u][i];
            if(!vis[v])
                rdfs(v,k);
        }
    }
    int n,A,B;
    int scc(){
        for(int i=0;i<2*n;i++)
            if(!vis[i])
                dfs(i);
        memset(vis,0,sizeof(vis));
        int k=0;
        for(int i=newg.size()-1;i>=0;i--){
            int v=newg[i];
            if(!vis[v])
                rdfs(v,k++);
        }
    }
    int main(){
        
        scanf("%d%d%d",&n,&A,&B);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i].val),a[i].id=i;
        sort(a,a+n);
        for(int i=0;i<n;i++){
            int pos=lower_bound(a,a+n,node{A-a[i].val,0})-a;
            if(pos!=n&&a[pos].val==A-a[i].val){
                addedge(a[i].id,a[pos].id);
                addedge(a[pos].id+n,a[i].id+n);
            }
            else{
                addedge(a[i].id,a[i].id+n);
            }
            
            pos=lower_bound(a,a+n,node{B-a[i].val,0})-a;
            if(pos!=n&&a[pos].val==B-a[i].val){
                addedge(a[i].id,a[pos].id);
                addedge(a[pos].id+n,a[i].id+n);
            }
            else{
                addedge(a[i].id+n,a[i].id);///这一步与上面处理相反是为了在输出归属方案时区别开来 
            }
        //    cout<<pos<<endl;
        }
        int k=scc();
        for(int i=0;i<n;i++){
            if(cmp[i]==cmp[i+n])
                return puts("NO"),0;
        }
        puts("YES");
        for(int i=0;i<n;i++){
            if(cmp[i]>cmp[i+n])
                printf("0 ");
            else
                printf("1 ");
        }
        return 0;
    }
    View Code

     题:http://poj.org/problem?id=3207

    题意:平面上,一个圆,圆的边上按顺时针放着n个点。现在要连m条边,
    比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。
    给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,
    使这些边都不相交。
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    const int M=2003;
    vector<int>g[M],rg[M],cb;
    int vis[M],cmp[M];
    void addedge(int u,int v){
        g[u].pb(v);
        rg[v].pb(u);
    }
    void dfs(int u){
        vis[u]=1;
        for(int i=0;i<g[u].size();i++)
            if(!vis[g[u][i]])
                dfs(g[u][i]);
        cb.pb(u);
    }
    void rdfs(int u,int k){
        vis[u]=1;
        cmp[u]=k;
        for(int i=0;i<rg[u].size();i++)
            if(!vis[rg[u][i]])
                rdfs(rg[u][i],k);
    }
    int n,m;
    int scc(){
        for(int i=0;i<2*n;i++)
            if(!vis[i])
                dfs(i);
        int k=0;
        memset(vis,0,sizeof(vis));
        for(int i=cb.size()-1;i>=0;i--){
            if(!vis[cb[i]])
                rdfs(cb[i],k++);
        }
        return k;
    }
    int a[M];
    vector<int>fuck;
    int main(){
        memset(a,-1,sizeof(a));
        scanf("%d%d",&n,&m);
        for(int u,v,i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            a[u]=v;
            a[v]=u;
            fuck.pb(u);
            fuck.pb(v); 
        }
        sort(fuck.begin(),fuck.end());
        for(int i=0;i<fuck.size();i++){
            for(int j=i+1;j<fuck.size();j++){
                int l=min(fuck[i],a[fuck[i]]),r=max(fuck[i],a[fuck[i]]);
                int L=min(fuck[j],a[fuck[j]]),R=max(fuck[j],a[fuck[j]]);
                if((l<L&&L<r&&R>r)||l<R&&R<r&&l>L){///代表这俩条线不能同时在圆内或圆外,即俩者矛盾 
                    addedge(fuck[i],fuck[j]+n);
                    addedge(fuck[j],fuck[i]+n);
                    addedge(fuck[i]+n,fuck[j]);
                    addedge(fuck[j]+n,fuck[i]);
                }
            }
        }
        int k=scc();
        for(int i=0;i<fuck.size();i++){
            int v=fuck[i];
            if(cmp[v]==cmp[v+n])
                return puts("the evil panda is lying again"),0;
        }
            
        puts("panda is telling the truth...");
        return 0;
    }
    View Code


  • 相关阅读:
    docker基础:docker网络模式
    WEB架构师成长之路之一-走正确的路(转载)
    DDD(领域驱动设计)
    C#泛型和泛型约束(转载)
    MES系统介绍
    vue中 computed和watch的一些简单理解(区别)(转载)
    sqlserver常用表值函数
    SQLServerAgent 当前未运行,因此无法将此操作通知它。
    浅谈敏捷开发(转载)
    认证、授权、鉴权和权限控制(转载)
  • 原文地址:https://www.cnblogs.com/starve/p/11747767.html
Copyright © 2011-2022 走看看