【题意】
给出n个牛棚、两个特殊点S1,S2的坐标。S1、S2直连。牛棚只能连S1或S2。还有,某些牛棚只能连在同一个S,某些牛棚不能连在同一个S。求使最长的牛棚间距离最小 距离是曼哈顿距离
【题解】
典型的2-sat判定。条件如下:
x hate y:x->~y,~y->x,~x->y,y->~x
x friend with y: x->y,y->x,~x->~y,~y->~x
二分最大距离limit,则有相应限制:
dist(i,S1)+dist(S1,j)>limit Xi->~Xj Xj->Xi
dist(i,S2)+dist(S2,j)>limit ~Xi->Xj ~Xj->Xi
dist(i,S1)+dist(S1,S2)+dist(S2,j)>limit Xi->Xj ~Xj->~Xi
dist(i,S2)+dist(S2,S1)+dist(S1,j)>limit ~Xi->~Xj Xj->Xi
【注意点】
对于2-sat判定,建图时逻辑要清晰,否则就会建错边。
【代码】
#include <iostream>
using namespace std;
const int maxn=1010;
const int maxe=maxn*maxn*2;
struct edge
{
int x,y,next;
}e[maxe];
int dfn[maxn],low[maxn],v[maxn],s[maxn],b[maxn],h[maxn];
int xa[maxn],xb[maxn],ya[maxn],yb[maxn],x[maxn],y[maxn],d[maxn];
int n,tot,cnt,ans,times,t,x1,x2,y1,y2,na,nb,ll,rr,mid,D;
void ins(int x,int y)
{
e[++tot].x=x;e[tot].y=y;
e[tot].next=h[x];h[x]=tot;
}
void tarjan(int x)
{
int y,i;
times++;t++;
dfn[x]=low[x]=times;
v[x]=1;s[t]=x;
for (i=h[x];i;i=e[i].next)
{
y=e[i].y;
if (v[y]==0)
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
if (v[y]==1)
low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x])
{
cnt++;
do
{
y=s[t--];
b[y]=cnt;v[y]=2;
}while (y!=x);
}
}
void build(int mid)
{
tot=0;
memset(h,0,sizeof(h));
int i,j;
for (i=1;i<=na;i++)
{
ins(xa[i],ya[i]+n);
ins(ya[i]+n,xa[i]);
ins(xa[i]+n,ya[i]);
ins(ya[i],xa[i]+n);
}
for (i=1;i<=nb;i++)
{
ins(xb[i],yb[i]);
ins(yb[i],xb[i]);
ins(xb[i]+n,yb[i]+n);
ins(yb[i]+n,xb[i]+n);
}
for (i=1;i<=n;i++)
for (j=i+1;j<=n;j++)
{
if (d[i]+d[j]>mid)
{
ins(i,j+n);
ins(j,i+n);
}
if (d[i+n]+d[j+n]>mid)
{
ins(i+n,j);
ins(j+n,i);
}
if (d[i]+d[j+n]+D>mid)
{
ins(i,j);
ins(j+n,i+n);
}
if (d[i+n]+d[j]+D>mid)
{
ins(i+n,j+n);
ins(j,i);
}
}
}
bool ok()
{
int i;
memset(v,0,sizeof(v));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(b,0,sizeof(b));
times=0;t=0;cnt=0;
for (i=1;i<=n;i++)
if (v[i]==0)
tarjan(i);
for (i=1;i<=n;i++)
if (b[i]==b[i+n])
return false;
return true;
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int i;
cin >> n >> na >> nb;
cin >> x1 >> y1 >> x2 >> y2;
for (i=1;i<=n;i++)
cin >> x[i] >> y[i];
for (i=1;i<=na;i++)
cin >> xa[i] >> ya[i];
for (i=1;i<=nb;i++)
cin >> xb[i] >> yb[i];
for (i=1;i<=n;i++)
{
d[i]=abs(x[i]-x1)+abs(y[i]-y1);
d[i+n]=abs(x[i]-x2)+abs(y[i]-y2);
}
D=abs(x1-x2)+abs(y1-y2);
ans=-1;
ll=1;rr=4000000;
while (ll<=rr)
{
mid=(ll+rr)/2;
build(mid);
if (ok())
ans=mid,rr=mid-1;
else
ll=mid+1;
}
cout << ans << endl;
return 0;
}