• HDU 3062 简单的2-SAT问题


    在2-SAT,最让我纠结的还是添加有向线段的函数了

    void add_clause(int i,int a,int j,int b)
    {
        int m=2*i+a;
        int n=2*j+b;
        G[m^1].push_back(n);
        G[n^1].push_back(m);
    }

    这里a,b因为只有真假两种情况,所以只取0或1,这里表示m V n是正确的,那么意思是取到m^1时,那么n必然得取到

    同理取到n^1时,m必然取到,所以两条有向线段就添加成功了

    例如这道题给所有夫妻排好序后,1号夫妻的丈夫,和3号夫妻的妻子有矛盾,那么来1号的妻子或3号中的丈夫是肯定成立的

    那添加量就可以写成add_clause(1,0,3,1)  (0表示妻子,1表示丈夫)

    最后添加进去的就是G[3].push_back(7),G[6].push_back(2);

    表示1号的丈夫来了,那只能让3号的丈夫来以及

    要是3号的妻子来,那么只能让1号的妻子来才不会有矛盾

    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]]=0;
                    if(!dfs(i^1)) return false;
                }
            }

        }
        return true;
    }

    solve()中查找遍所有的夫妻对,表示当且仅当夫妻二人都不能来的时候返回false,否则返回true

    总代码如下:

    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    #define N 1005*2
    bool mark[N];
    vector<int> G[N];
    int n,c,S[N];
    bool dfs(int i)
    {
        if(mark[i^1]) return false;
        if(mark[i]) return true;
        mark[i]=true;
        S[c++]=i;
        for(int j=0;j<G[i].size();j++)
            if(!dfs(G[i][j])) return false;
        return true;
    }
    void init()
    {
        for(int i=0;i<N;i++) G[i].clear();
        memset(mark,false,sizeof(mark));
        memset(S,0,sizeof(S));
    }
    void add_clause(int i,int a,int j,int b)
    {
        int m=2*i+a;
        int n=2*j+b;
        G[m^1].push_back(n);
        G[n^1].push_back(m);
    }
    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]]=0;
                    if(!dfs(i^1)) return false;
                }
            }
    
        }
        return true;
    }
    int main()
    {
        int m,a1,a2,c1,c2;
        while(scanf("%d%d",&n,&m)!=EOF){
            init();
            for(int i=0;i<m;i++){
                scanf("%d%d%d%d",&a1,&a2,&c1,&c2);
                add_clause(a1,c1^1,a2,c2^1);
            }
            if(solve()) printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    WPF分页控件
    Anroid图标尺寸
    linux常用快捷键
    securecrt中vim行号下划线问题及SecureCRT里root没有高亮的设置,修改linux终端命令行颜色
    ANT-普通替换和正则替换
    js实现IOS上删除app时颤抖动画j函数
    php语法错误导致服务器错误(500)解决
    Linux 常用命令大全2
    Linux 命令行快捷键
    backbone源代码注释(部分)
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/3894285.html
Copyright © 2020-2023  润新知