您的位置:首页 > 产品设计 > UI/UE

POJ 2749 Building roads【二分+2-sat】

2012-10-01 14:49 387 查看
题意: 已知有 n 个农场,知道了每个农场的坐标,有两个中转站 s1,s2, 每个农场和其中一个中转站相连,

有 A 对hate关系 a,b 表示 a 和 b 农场不能和同一个中转站相连,

有 B 对Fs 关系 a,b 表示 a 和 b 农场必须和同一个中转站相连,

求一种连接方案,在满足条件 A,B的条件下,图中任意两个农场的最大距离最小。

分析: i 表示第 i 个农场和中转站 s1 相连,i + n 表示第 i 个农场和中转站 s2 相连,

   建图:

在 A 条件中,对于每对关系 i , j 连边

i -> j + n

i + n -> j

j ->i + n

j + n ->i

表示 i 和 j 不能和同一个中转站相连

在 B 条件中,对于没对关系的建边方式和上面类似,

对每一次枚举的 距离 di,

枚举任意两个农场 i , j

如果 距离 i->s1->j 大于 di , 连边

i -> j+n , j -> i+n 表示 i , j 农场不能同时和 s1 相连

如果 距离 i->s2->j 大于 di , 连边

i + n -> j , j + n -> i 表示 i , j 农场不能同时和 s2 相连

如果 距离 i->s1->s2->j 大于 di ,连边

i -> j , j + n -> i + n 表示 如果 i 农场和 s1 相连,则 j 农场必须和 s1 相连,如果 j 农场和 s2 相连,则 i 必须和s2 相连

如果 距离 i->s2->s1->j 大于 di ,连边

j -> i , i + n -> j + n 表示 如果 j 农场和 s1 相连,则 i 农场必须和 s1 相连,如果 i 农场和 s2 相连,则 j 必须和s2 相连

对于每次枚举的距离 di 判断是否有冲突情况即可。

#include<stdio.h>
#include<string.h>
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
#define max(a,b)(a)>(b)?(a):(b)
#define maxn 1005
#define maxm 1000000
struct node
{
int to,next;
}e[maxm];
int tot;
int head[maxn];
void add(int s,int t)
{
e[tot].to=t;
e[tot].next=head[s];
head[s]=tot++;
}
int ti,sn,top,n;
int dfn[maxn];
int low[maxn];
int ins[maxn];
int sta[maxn];
int col[maxn];
void tarjan(int u)
{
dfn[u]=low[u]=++ti;
ins[u]=1;
sta[++top]=u;
int i,k;
for(i=head[u];i;i=e[i].next)
{
k=e[i].to;
if(dfn[k]==0)
{
tarjan(k);
low[u]=min(low[u],low[k]);
}
else if(ins[k])
low[u]=min(low[u],dfn[k]);
}
if(dfn[u]==low[u])
{
sn++;
do
{
k=sta[top--];
ins[k]=0;
col[k]=sn;
}while(k!=u);
}
}
struct point
{
int x,y;
}p[maxn],s1,s2;
int ab(int x)
{  return x>0?x:-x; }
int dis(point a,point b)
{
return ab(a.x-b.x)+ab(a.y-b.y);
}
struct Fs
{
int a,b;
}hate[1005],fs[1005];
int A,B;
int g[505][505];
bool ok(int di)
{
tot=1;
clr(head);
int i,j;
for(i=1;i<=A;i++)
{
add(hate[i].a,hate[i].b+n);
add(hate[i].a+n,hate[i].b);
add(hate[i].b,hate[i].a+n);
add(hate[i].b+n,hate[i].a);
}
for(i=1;i<=B;i++)
{
add(fs[i].a,fs[i].b);
add(fs[i].a+n,fs[i].b+n);
add(fs[i].b,fs[i].a);
add(fs[i].b+n,fs[i].a+n);
}
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(g[0][i]+g[0][j]>di)
add(i,j+n),add(j,i+n);
if(g[i][0]+g[j][0]>di)
add(i+n,j),add(j+n,i);
if(g[0][i]+g[0][0]+g[j][0]>di)
add(i,j),add(j+n,i+n);
if(g[0][j]+g[0][0]+g[i][0]>di)
add(j,i),add(i+n,j+n);
}
sn=top=ti=0;
clr(dfn);
for(i=1;i<=2*n;i++)
if(!dfn[i])
tarjan(i);
for(i=1;i<=n;i++)
if(col[i]==col[i+n])
return 0;
return 1;
}
int main()
{
int i,j,k;
while(scanf("%d%d%d",&n,&A,&B)!=EOF)
{
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);
int l=0,r=5000000,mid,res;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
g[i][j]=g[j][i]=dis(p[i],p[j]);
for(i=1;i<=n;i++)
{
g[0][i]=dis(s1,p[i]);
g[i][0]=dis(p[i],s2);
}
g[0][0]=dis(s1,s2);
for(i=1;i<=A;i++)
scanf("%d%d",&hate[i].a,&hate[i].b);
for(i=1;i<=B;i++)
scanf("%d%d",&fs[i].a,&fs[i].b);
res=-1;
while(l<=r)
{
mid=(l+r)>>1;
if(ok(mid))
{
res=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: