POJ_2749 Building roads 2-Sat

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 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值