http://poj.org/problem?id=2749
题意:
有N个牛棚,2个中转站,每个牛棚只能选择一个中转站并连接到该中转站,求任意
两个在同一个中转站中的牛棚之间的最大距离的最小值。
思路:
"最大值最小化"的问题都可以用“二分法”,本题也不例外,其次就是建图用2-sat求解,
建图的规则是:
如果d1[i] + d1[j] > mid 则说明i号牛棚和j号牛棚不能同时连接到0号中转站,则加边(i , j+N) ;
d1[i] + d2[j] + D > mid 则说明i号牛棚连0时,j号牛棚不能连j ,加边(i , j)
d2[i] + d1[j] + D > mid , 同理加边 (i+N ,j + N) ;
d2[i] + d2[j] > mid 加边 (i+N, j) ;
最后还需要加上hate和like 的条件。
总结:2-Sat问题建图的时候,可以通过找不能满足的条件来建图,即通过找到一组不可能的情况从而推出一组确定的边 。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int N ,A, B , D;
int sx[2] , sy[2] ;
int x[550] , y[550] ;
const int MAXN = 510*2 ;
int Gv[MAXN*MAXN] , Gnext[MAXN*MAXN] , Gr[MAXN] ,Gc ;
int dfn[MAXN] , low[MAXN] ,stack[MAXN] , belong[MAXN] ;
int top ,idx , Bcnt ;
bool hate[510][510] , in[MAXN];
bool like[510][510] ;
int d1[MAXN] , d2[MAXN] ;
void add(int a, int b){
Gv[Gc] = b ;
Gnext[Gc] = Gr[a] ;
Gr[a] = Gc++ ;
}
void tarjin(int u){
int v ;
low[u] = dfn[u] = ++idx ;
stack[++top] = u ; in[u] = 1 ;
for(int i=Gr[u] ;i!=-1;i=Gnext[i]){
v = Gv[i] ;
if( !dfn[v] ){
tarjin(v) ;
if( low[v] < low[u])
low[u] = low[v] ;
}
else if(in[v] && dfn[v] < low[u])
low[u] = dfn[v] ;
}
if( low[u] == dfn[u] ){
Bcnt++ ;
do{
v = stack[top--] ; in[v] = 0 ;
belong[v] = Bcnt ;
}while(u != v) ;
}
}
int MAX(int a, int b){
return a > b ? a : b ;
}
bool solve(int mid){
memset(Gr , -1 ,sizeof(Gr)) ; Gc = 0 ;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
if(i == j) continue ;
if( d1[i] + d1[j] > mid ){
add(i , j+N);
}
if( d1[i] + d2[j] + D > mid){
add(i , j);
}
if( d2[i] + d1[j] + D > mid){
add(i+N, j+N);
}
if( d2[i] + d2[j] > mid){
add(i+N,j);
}
if(hate[i][j] == 1 ){
add(i,j+N);
add(i+N,j);
}
if( like[i][j] == 1){
add(i,j) ;
add(i+N,j+N);
}
}
}
top = idx = Bcnt = 0 ;
memset(dfn , 0 ,sizeof(dfn));
memset(in, 0, sizeof(in)) ;
for(int i=1;i<=2*N;i++){
if( !dfn[i] ) tarjin(i) ;
}
for(int i=1;i<=N;i++){
if( belong[i] == belong[i+N] ) return false ;
}
return true ;
}
void deal(){
int l , h , m ;
l = 0 ; h = 5000000 ;
while( l < h ){
m = (l + h) >> 1 ;
if( solve(m) ){
h = m ;
}
else
l = m + 1 ;
}
if(l == 5000000 )
printf("-1\n");
else
printf("%d\n",l) ;
}
int main(){
int a ,b ;
while(scanf("%d%d%d",&N,&A,&B) == 3){
for(int i=0;i<2;i++) scanf("%d%d",&sx[i],&sy[i]);
D = abs(sx[0] - sx[1]) + abs(sy[0] - sy[1]);
for(int i=1;i<=N;i++){
scanf("%d%d",&x[i],&y[i]);
}
memset(hate , 0 ,sizeof(hate));
memset(like, 0,sizeof(like)) ;
for(int i=1;i<=A;i++){
scanf("%d%d",&a,&b);
hate[a][b] = hate[b][a] = 1;
}
for(int i=1;i<=B;i++){
scanf("%d%d",&a,&b);
like[a][b] = like[b][a] = 1 ;
}
for(int i=1;i<=N;i++){
d1[i] = abs( x[i] - sx[0] ) + abs( y[i] - sy[0] ) ;
d2[i] = abs( x[i] - sx[1] ) + abs( y[i] - sy[1] ) ;
}
deal() ;
}
return 0 ;
}