POJ-2749-Building roads(2-sat)

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;
}

 

posted @ 2013-02-05 23:02  z.arbitrary  阅读(228)  评论(0编辑  收藏  举报