poj 2749 2-SAT问题

思路:首先将hate和friend建边求其次2-SAT问题,判断是否能有解,没解就输出-1,否则用二分枚举最大的长度,将两个barn的距离小于mid的看做是矛盾,然后建边,求2-SAT问题。找出最优解。

#include<iostream>

#include<cstring>

#include<cstdio>

#include<algorithm>

#include<cmath>

#include<vector>

#define Maxn 3010

#define Maxm 1000000

using namespace std;

int dfn[Maxn],low[Maxn],vi[Maxn],head[Maxn],e,n,m,lab,top,Stack[Maxn],num,id[Maxn],A,B,ss;

struct Edge{

    int u,v,next,l;

}edge[Maxm];

struct Point{

    int x,y;

}p[Maxn],s1,s2;

struct Match{

    int a,b;

}hate[Maxn],Friend[Maxn];

void init()

{

    int i,j;

    memset(dfn,0,sizeof(dfn));

    memset(low,0,sizeof(low));

    memset(head,-1,sizeof(head));

    memset(id,0,sizeof(id));

    memset(vi,0,sizeof(vi));

    e=lab=num=top=0;

}

void add(int u,int v)

{

    edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;

}

int Dis(Point a,Point b)

{

    return abs(a.x-b.x)+abs(a.y-b.y);

}

void Tarjan(int u)

{

    int i,j,v;

    dfn[u]=low[u]=++lab;

    Stack[top++]=u;

    vi[u]=1;

    for(i=head[u];i!=-1;i=edge[i].next)

    {

        v=edge[i].v;

        if(!dfn[v])

        {

            Tarjan(v);

            low[u]=min(low[u],low[v]);

        }

        if(vi[v])

        low[u]=min(low[u],dfn[v]);

    }

    if(low[u]==dfn[u])

    {

        ++num;

        do{

            i=Stack[--top];

            vi[i]=0;

            id[i]=num;

        }while(i!=u);

    }

}

void build(int mid)

{

    int i,j;

    init();

    for(i=1;i<=n;i++)

        for(j=1;j<=n;j++){

                if(j==i)

                continue;

        if(Dis(p[i],s1)+Dis(p[j],s1)>mid)

        {

            add(i,j+n);

            add(j,i+n);

        }

        if(Dis(p[i],s2)+Dis(p[j],s2)>mid)

        {

            add(i+n,j);

            add(j+n,i);

        }

        if(Dis(p[i],s1)+Dis(p[j],s2)+ss>mid)

        {

            add(i,j);

            add(j+n,i+n);

        }

        if(Dis(p[i],s2)+Dis(p[j],s1)+ss>mid)

        {

            add(j,i);

            add(i+n,j+n);

        }

    }

    for(i=1;i<=A;i++)

    {

        add(hate[i].a,hate[i].b+n);

        add(hate[i].b,hate[i].a+n);

        add(hate[i].a+n,hate[i].b);

        add(hate[i].b+n,hate[i].a);

    }

    for(i=1;i<=B;i++)

    {

        add(Friend[i].a,Friend[i].b);

        add(Friend[i].a+n,Friend[i].b+n);

        add(Friend[i].b,Friend[i].a);

        add(Friend[i].b+n,Friend[i].a+n);

    }

}

int cal()

{

    int i;

    for(i=1;i<=n*2;i++)

    {

        if(!dfn[i])

            Tarjan(i);

    }

    for(i=1;i<=n;i++)

    {

            if(id[i]==id[i+n])

            return 0;

    }

    return 1;

}

int solve()

{

    int i,j;

    for(i=1;i<=A;i++)

    {

        add(hate[i].a,hate[i].b+n);

        add(hate[i].b,hate[i].a+n);

        add(hate[i].a+n,hate[i].b);

        add(hate[i].b+n,hate[i].a);

    }

    for(i=1;i<=B;i++)

    {

        add(Friend[i].a,Friend[i].b);

        add(Friend[i].a+n,Friend[i].b+n);

        add(Friend[i].b,Friend[i].a);

        add(Friend[i].b+n,Friend[i].a+n);

    }

    if(!cal())

        return -1;

    int l,r,mid;

    l=0;r=4000010;

    while(l+1<r)

    {

        mid=(l+r)>>1;

        build(mid);

        if(cal())

            r=mid;

        else

            l=mid;

    }

    return r;

}

int main()

{

    int i,j,a,b,c;

    while(scanf("%d%d%d",&n,&A,&B)!=EOF)

    {

        init();

        scanf("%d%d%d%d",&s1.x,&s1.y,&s2.x,&s2.y);

        for(i=1;i<=n;i++)

            scanf("%d%d",&p[i].x,&p[i].y);

        for(i=1;i<=A;i++)

            scanf("%d%d",&hate[i].a,&hate[i].b);

        for(i=1;i<=B;i++)

            scanf("%d%d",&Friend[i].a,&Friend[i].b);

        ss=Dis(s1,s2);

        printf("%d\n",solve());

    }

    return 0;

}

 

你可能感兴趣的:(poj)