POJ 2749 Building roads(2-ST)

题目链接:http://poj.org/problem?id=2749

题意:给出n个牛棚。两个特殊点S1,S2的坐标。S1、S2直接相连。牛棚只能连S1或S2,还有一些限制:某些牛棚(friend)只能连在同一个S,某些牛棚(hate)不能连在同一个S。求一种连法使得最长的牛棚间距离最小(距离是曼哈顿距离)

思路:二分枚举最大值mid,然后重新构图,用2-SAT判定可行性。用Xi表示第i个牛棚连到S1,~Xi表示连到S2。检查每一个约束条件,构图:

1、hate关系的i,j     Xi->~Xj  ~Xi->Xj  Xj->~Xi  ~Xj->Xi

2、friend关系的i,j    Xi->Xj  ~Xi->~Xj  Xj->Xi  ~Xj->~Xi

3、dist(i,S1)+dist(S1,j)>mid            Xi->~Xj  Xj->~Xi

   dist(i,S2)+dist(S2,j)>mid            ~Xj->Xi  ~Xi->Xj

   dist(i,S1)+dist(S1,S2)+dist(S2,j)>mid  Xi->Xj  ~Xj->~Xi

   dist(i,S2)+dist(S2,S1)+dist(S1,j)>mid  ~Xi->~Xj  Xj->Xi

 

 #include <stdio.h>

 #include <string.h>

 #include <stack>

 #define min(x,y) ((x)<(y)?(x):(y))

 using namespace std;

 

 struct node

 {

     int v,next;

 };

 

 struct Point

 {

     int x,y;

 };

 

 

 const int INF=1000000000;

 node edges[3000000];

 int head[1505],dfn[1505],low[1505],visit[1505],color[1505];

 int n,A,B,e,index,cnt;

 stack<int> S;

 Point s1,s2,p[1505],h[1505],f[1505];

 

 

 

 void InPut()

 {

     int i;

     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",&h[i].x,&h[i].y);

     for(i=1;i<=B;i++) scanf("%d%d",&f[i].x,&f[i].y);

 }

 

 

 void Add(int u,int v)

 {

     edges[e].v=v;

     edges[e].next=head[u];

     head[u]=e++;

 }

 

 

 

 void Tarjan(int u)

 {

     int i,v;

     

     low[u]=dfn[u]=++index;S.push(u);visit[u]=1;

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

     {

         v=edges[i].v;

         if(!dfn[v])

         {

             Tarjan(v);

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

         }

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

     }

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

     {

         cnt++;

         do

         {

             v=S.top();

             S.pop();

             visit[v]=0;

             color[v]=cnt;

         }while(u!=v);

     }

 }

 

 

 

 

 int TWO_ST()

 {

     int i;

     

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

     memset(visit,0,sizeof(visit));

     index=cnt=0;

     while(!S.empty()) S.pop();

     for(i=1;i<=2*n;i++) if(!dfn[i]) Tarjan(i);

     for(i=1;i<=n;i++) if(color[i]==color[i+n]) return 0;

     return 1;

 }

 

 int ABS(int x)

 {

     return x>0?x:-x;

 }

 

 int Dis(Point a,Point b)

 {

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

 }

 

 int OK(int mid)

 {

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

     e=0;

     int i,j;

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

     {

         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(s1,s2)+Dis(s2,p[j])>mid) Add(i,j),Add(j+n,i+n);

         if(Dis(p[i],s2)+Dis(s1,s2)+Dis(s1,p[j])>mid) Add(i+n,j+n),Add(j,i);

     }

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

     {

         Add(h[i].x,h[i].y+n);

         Add(h[i].x+n,h[i].y);

         Add(h[i].y,h[i].x+n);

         Add(h[i].y+n,h[i].x);

     }

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

     {

         Add(f[i].x,f[i].y);

         Add(f[i].x+n,f[i].y+n);

         Add(f[i].y,f[i].x);

         Add(f[i].y+n,f[i].x+n);

     }

     return TWO_ST();

 }

 

 void Deal()

 {

     int low=0,high=INF,mid;

 

     while(low<=high)

     {

         mid=(low+high)>>1;

         if(OK(mid)) high=mid-1;

         else low=mid+1;

     }

     if(OK(high)) printf("%d\n",high);

     else if(OK(low)) printf("%d\n",low);

     else puts("-1");

 }

 

 int main()

 {

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

         InPut(),Deal();

     return 0;

 }

 

  

 

你可能感兴趣的:(Build)