zoukankan      html  css  js  c++  java
  • 2-SAT入门 poj2749 Building roads hdu4421 Bit Magic

    poj2749 Building roads

    http://poj.org/problem?id=2749

    二分答案,以后构造布尔表达式。

      相互讨厌是!((a and b)or(!a and !b) 化简得 (!a or !b)and(a or b)

      相互喜欢是!(a and !b)or(!a and b) 化简得 (!a or b)and(a or !b)

      然后枚举点对讨论一个点对和S1,S2相连会不会超过lim来添加限制。

        一共有四种情况都差不多,比如都连到S1会超过lim,就添加!(!a and !b) 化简得 (a or b)

    构造表达式的时候可以从三个层次考虑,一个是直接写!()描述不允许出现的情况,然后化简。也可以考虑要排除什么情况,从什么变量取值使得子句为假出发,直接构造得到化简后的表达式。也可以从图上考虑,不通过dd_clause将子句化成蕴含的形式,直接考虑,谁向谁连边。比如相互喜欢就是四条边<a真,b真> <b假,a假><a假,b假><b真,a真>。

    我觉得第一种比较好。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring>
    using namespace std;
    
    typedef pair<int,int> Point;
    //点的标号从0开始到2n-1
    const int maxn = 500 + 10 ;
    const int maxm = 1000 + 10 ;
    struct TwoSAT
    {
        int n;
        vector<int> G[maxn*2];
        bool mark[maxn*2];
        int S[maxn*2],c;
    
        bool dfs(int x){
            if(mark[x^1]) return 0;
            if(mark[x  ]) return 1;
            mark[x] = 1;
            S[c++]  = x;
            for (int i = 0; i < G[x].size(); ++i)
                if(!dfs(G[x][i])) return 0;
            return 1;
        }
    
        void init(int n){
            this->n = n;
            for (int i = 0; i < n*2; ++i)
                G[i].clear();
            memset(mark,0,sizeof(mark));
        }
    
        // x = xval or y = yval
        void add_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);
        }
    
        bool solve(){
            for (int i = 0; i < n*2; 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 0;
                    }
                }
            return 1;
        }
    };
    
    TwoSAT TSAT;
    Point S[3],P[maxn];
    pair<int,int> hate[maxm],like[maxm];
    
    int N,A,B,SS;
    
    int dis(Point P,Point Q){return abs(P.first-Q.first)+abs(P.second-Q.second);}
    
    bool ok(int lim){
        TSAT.init(N);
        for (int i = 0; i < A; ++i){
            TSAT.add_clause(hate[i].first,0,hate[i].second,0);
            TSAT.add_clause(hate[i].first,1,hate[i].second,1);
        }
        for (int i = 0; i < B; ++i){
            TSAT.add_clause(like[i].first,0,like[i].second,1);
            TSAT.add_clause(like[i].first,1,like[i].second,0);
        }
        for (int i = 0; i < N; ++i)
            for (int j = i+1; j < N; ++j){
                int i0 = dis(P[i],S[0]),
                    i1 = dis(P[i],S[1]),
                    j0 = dis(P[j],S[0]),
                    j1 = dis(P[j],S[1]);
                if(i0+j0>lim)
                    TSAT.add_clause(i,1,j,1);
                if(i1+j1>lim)
                    TSAT.add_clause(i,0,j,0);
                if(i0+SS+j1>lim)
                    TSAT.add_clause(i,1,j,0);
                if(i1+SS+j0>lim)
                    TSAT.add_clause(i,0,j,1);
            }
        return TSAT.solve();
    }
    
    int main()
    {
    
        Point S1,S2;
        while(cin>>N>>A>>B){
            cin>>S[0].first>>S[0].second>>S[1].first>>S[1].second;
            SS=dis(S[0],S[1]);
            for (int i = 0; i < N; ++i)
                cin>>P[i].first>>P[i].second;
    
            for (int i = 0; i < A; ++i){
                cin>>hate[i].first>>hate[i].second;
                hate[i].first--;
                hate[i].second--;
            }
            for (int i = 0; i < B; ++i){
                cin>>like[i].first>>like[i].second;
                like[i].first--;
                like[i].second--;
            }
    
            if(!ok(4000000)){
                cout<<-1<<endl;
                continue;
            }
    
            int l=0,r=4000000,mid=(l+r)>>1;
            for(;l<r-1;mid=(l+r)>>1)
                if(ok(mid))
                    r=mid;
                else
                    l=mid;
    
            cout<<r<<endl;
        }
        return 0;
    }

    hdu4421 Bit Magic

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

    按位做,变成32个问题。把题目给的逻辑函数(i ope j equal bval)对应的最大项表达式找到。需要注意的是,出现(i && j)可以处理成(i||i)&&(j||j)。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    
    using namespace std;
    
    inline int min(int a,int b) { return a<b? a: b ; }
    const int maxn =  4000 +10  ;
    const int maxm =  4000000 + 10;
    struct  TwoSAT {
        int col[maxn],dfn[maxn],low[maxn],s[maxn],cnt,scnt, stop,n;
        int pre[maxm],ad[maxn],v[maxm], tot ;
    
        void init()
        {
            tot=0 ;
            memset(ad,0,sizeof(ad));
        }
        void add(int x,int y)
        {
            pre[++tot] = ad[x];
            ad[x] = tot ;
            v[tot] = y; 
        }
        void add_clause(int x, int xval, int y, int yval)
        {
            add(x+xval*n,y+(!yval)*n);
            add(y+yval*n,x+(!xval)*n);
        }
        void dfs(int u) {
            dfn[u]=low[u]=++cnt ;
            s[++stop]=u;
            for (int j=ad[u];j;j=pre[j]){
                if (!dfn[v[j]]){
                    dfs(v[j]);
                    low[u] = min(low[u],low[v[j]]) ;
                }
                else if (!col[v[j]]) 
                    low[u] = min(low[u] , dfn[v[j]]); 
            }
            if(low[u]==dfn[u]){
                ++scnt; 
                while(1){
                    int x=s[stop--];
                    col[x]=scnt; 
                    if(x==u)break; 
                }
            }
        }
        bool slove()
        {
            memset(dfn,0,sizeof(dfn));
            memset(col,0,sizeof(col));
            cnt=scnt=stop= 0 ; 
            for (int i=0; i<2*n; ++i)
                if (!dfn[i])
                    dfs(i);
            for(int i=0;i<n;++i)
                if (col[i] ==col[i+n])
                    return 0;
            return 1;
        }
    };
    
    TwoSAT TSAT; 
    
    int b[600][600]; 
    int main()
    {
        int n ; 
        while (scanf("%d",&n)!=EOF) {
            for (int i=0; i<n; ++i) 
                for (int j=0; j<n; ++j) 
                    scanf("%d",&b[i][j]) ; 
            TSAT.n=n;
            int flag = 1; 
            for (int k=0; k<31; ++k) {
                TSAT.init() ; 
                for (int i=0; i<n; ++i) 
                    for (int j=i; j<n; ++j)
                    if (i==j)
                        continue; 
                    else if (i %2 ==1 && j%2 ==1) {
                        if (b[i][j] & (1<<k)){
                            TSAT.add_clause(i,1,j,1);
                        }
                        else{
                            TSAT.add_clause(i,0,i,0);
                            TSAT.add_clause(j,0,j,0);
                        }
                    }
                    else if (i%2==0 && j%2==0) {
                        if (b[i][j] & (1<<k)){
                            TSAT.add_clause(i,1,i,1);
                            TSAT.add_clause(j,1,j,1);
                        }
                        else {
                            TSAT.add_clause(i,0,j,0);
                        }
                    } 
                    else {
                        if (b[i][j] & (1<<k)) {
                            TSAT.add_clause(i,0,j,0);
                            TSAT.add_clause(i,1,j,1);
                        }
                        else {
                            TSAT.add_clause(i,0,j,1);
                            TSAT.add_clause(i,1,j,0);
                        }
                    }
                    flag = TSAT.slove();
                //printf("%d %d
    ",k,flag); 
                if (!flag) break ; 
            }
            if (flag) puts("YES"); else puts("NO"); 
        }
    }
  • 相关阅读:
    python实现布隆过滤器及原理解析
    gin框架源码解析
    阿里云docker操作问题记录
    Qt编写数据可视化大屏界面电子看板系统
    CSS3-3D制作案例分析实战
    前端可视化项目流程,涉及three.js(webGL),3DMax技术,持续更新
    前端可视化项目流程,涉及three.js(webGL),3DMax技术,持续更新
    jquery拖拽排序,针对后台列表table进行拖拽排序(Echart不刷新页面,多语言切换下的地图数据重新加载,api请求数据加载
    Java 设置Excel条件格式(高亮条件值、应用单元格值/公式/数据条等类型)C# 创建Excel气泡图
    Java 如何在PPT中设置形状组合、取消组合、编辑组合形状
  • 原文地址:https://www.cnblogs.com/lijianlin1995/p/3844813.html
Copyright © 2011-2022 走看看