zoukankan      html  css  js  c++  java
  • POJ2749Building roads(2sat)

    POJ 2-sat六题最后一题

    http://blog.sina.com.cn/s/blog_64675f540100k2xf.html

    poj 六道2-sat最后一题第六题:

    题目描述:有n个农场,每个农场有坐标x,y。

    有两个集合点s1和s2(也有坐标),每个农场必须连接其中的一个(有且仅有一个)。

    然后有A个条件,每个条件a,b表示a农场不能和b农场连接在一个集合点。

    然后再有B个条件,每个条件a,b表示a农场必须和b农场连接在一个集合点。

    问你,在各种合法的连接情况中,任何两个农场间的距离的最大值的最小值是多少。

    解题报告:

    每个农场i分成两个点,i和i + n,前面表示连接左侧集合点,后面的表示连接右侧集合点。

    对于条件A中的ab,连接

    <a, b + n> <a + n, b> <b, a + n> <b + n, a>

    这样就保证了ab不再一个集合点。同理,B条件也很好写。

    然后就是用二分枚举答案(距离的最大值)。

    对于每一次枚举的答案key,枚举任意两个农场a,b, 如果他俩的4种距离(a->s1->s1>b, a->s2->s2->b, a->s1->s2->b, a->s2->s1->b)有大于key的,就加入判定条件,不能这样连接。

    // File Name: 2749.cpp
    // Author: zlbing
    // Created Time: 2013/2/5 21:18:58
    
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstring>
    #include<stack>
    #include <cmath>
    using namespace std;
    #define MAXN 1000
    struct TwoSAT{
        int n;
        vector<int>G[MAXN*2];
        bool mark[MAXN*2];
        stack<int>S;
        bool dfs(int x)
        {
            if(mark[x^1])return false;
            if(mark[x])return true;
            mark[x]=true;
            S.push(x);
            for(int i=0;i<G[x].size();i++)
            {
                int v=G[x][i];
                if(!dfs(v))return false;
            }
            return true;
        }
        void init(int _n)
        {
            n=_n;
            for(int i=0;i<2*n;i++)
                G[i].clear();
            memset(mark,0,sizeof(mark));
        }
        void add_clause(int x,int y)
        {
            G[x].push_back(y);
        }
        bool solve()
        {
            for(int i=0;i<2*n;i=i+2)
            {
                if(!mark[i]&&!mark[i+1]){
                      while(!S.empty())
                      {
                          S.pop();
                      }
                    if(!dfs(i))
                    {
                        while(!S.empty())
                        {
                            mark[S.top()]=false;
                            S.pop();
                        }
                        if(!dfs(i+1))return false;
                    }
                }
            }
    
    //        for(int i=0;i<2*n;i++)
    //            if(mark[i])printf("%d ",T[i/2][i%2]);
    //        printf("\n");
            return true;
        }
    };
    int N,A,B;
    int s[2][2];
    int d[MAXN][2];
    int d1[MAXN][2];
    int d2[MAXN][2];
    int AlenB;
    TwoSAT solver;
    int count(int i,int j)
    {
        return abs(d[i][0]-s[j][0])+abs(d[i][1]-s[j][1]);
    }
    bool test(int M)
    {
        solver.init(N);
        for(int i=0;i<A;i++)
        {
            solver.add_clause(d1[i][0]*2,d1[i][1]*2+1);
            solver.add_clause(d1[i][0]*2+1,d1[i][1]*2);
            solver.add_clause(d1[i][1]*2+1,d1[i][0]*2);
            solver.add_clause(d1[i][1]*2,d1[i][0]*2+1);
        }
        for(int i=0;i<B;i++)
        {
            solver.add_clause(d2[i][0]*2,d2[i][1]*2);
            solver.add_clause(d2[i][0]*2+1,d2[i][1]*2+1);
            solver.add_clause(d2[i][1]*2,d2[i][0]*2);
            solver.add_clause(d2[i][1]*2+1,d2[i][0]*2+1);
        }
        for(int i=0;i<N;i++)
            for(int j=i+1;j<N;j++)
            {
                if(count(i,0)+count(j,0)>M)
                {
                    solver.add_clause(i*2,j*2+1);
                    solver.add_clause(j*2,i*2+1);
                }
                if(count(i,1)+count(j,1)>M)
                {
                    solver.add_clause(i*2+1,j*2);
                    solver.add_clause(j*2+1,i*2);
                }
                if(count(i,1)+count(j,0)+AlenB>M)
                {
                    solver.add_clause(i*2+1,j*2+1);
                    solver.add_clause(j*2,i*2);
                }
                if(count(i,0)+count(j,1)+AlenB>M)
                {
                    solver.add_clause(i*2,j*2);
                    solver.add_clause(j*2+1,i*2+1);
                }
            }
            if(solver.solve())return true;
            else return false;
    }
    #define MAXN 4000000
    int main(){
        while(~scanf("%d%d%d",&N,&A,&B))
        {
            scanf("%d%d%d%d",&s[0][0],&s[0][1],&s[1][0],&s[1][1]);
            AlenB=abs(s[0][0]-s[1][0])+abs(s[0][1]-s[1][1]);
            for(int i=0;i<N;i++)
                scanf("%d%d",&d[i][0],&d[i][1]);
            int a,b;
            for(int i=0;i<A;i++)
            {
                scanf("%d%d",&a,&b);
                d1[i][0]=--a;
                d1[i][1]=--b;
            }
            for(int i=0;i<B;i++)
            {
                scanf("%d%d",&a,&b);
                d2[i][0]=--a;
                d2[i][1]=--b;
            }
            int L=0,R=MAXN;
            while(L<R)
            {
                int mid=L+(R-L)/2;
                if(test(mid)){
                    R=mid;
                }
                else L=mid+1;
            }
            if(R==MAXN)printf("-1\n");
            else
            printf("%d\n",R);
        }
        return 0;
    }
  • 相关阅读:
    人为什么会生气 --- 答案是什么?
    职场中我们常犯的8个错误
    职场上最常见的20条错误,犯三条就够致命啦
    C语言,基于单向链表实现,变长动态数据缓冲区(线程安全) ---- 类似java的StringBuffer --- 亲测OK
    门限签名
    基于RSA的实用门限签名算法
    图解密码技术(第3版)-第4章
    各种加密算法比较
    密码那点事儿
    数字签名,我有疑问。
  • 原文地址:https://www.cnblogs.com/arbitrary/p/2893494.html
Copyright © 2011-2022 走看看