HDU_1824 Let's go home 2-Sat

本文介绍了一道典型的2-SAT问题,通过构建图模型解决ACM集训队人员安排难题。针对N支队伍及其成员限制条件,利用Tarjan算法进行强连通分量分析,最终确定可行方案的存在性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.hdu.edu.cn/showproblem.php?pid=1824

题意:

acm集训队有N只队伍,每只队伍有3人,其中1人为队长,另外两人都队员,

现在需要安排回家休息,每只队伍要么队长回家,要么两名队员同时回家休息。 给

出M组队员的信息,每组为(a,b)表示的是队员a和队员b不能同时留下也不能同时回

家,问是否存在可行的方案。

思路:

2-Sat问题,对于每个队,留校的要么是队长,要么是两个队员,因此这就是典型

的2-Sat模型,可以将两个队员看成是一个点,建图就是按照题目中给的信息来建,

最后用tarjin缩点并判断是否存在解即可。


代码:

#include<stdio.h>
#include<string.h>
int N ,M ;
int a1[1010] , a2[2][1010] ;
int nn[3*1010] ;
int be[3*1010] ;
const int MAXN = 1010*2 ;
int Gr[MAXN] , Gv[MAXN*MAXN] , Gnext[MAXN*MAXN] , Gc ;
int fa[MAXN] ;
int dfn[MAXN] , low[MAXN] , stack[MAXN] , belong[MAXN] ;
bool in[MAXN] ;
int top, idx ,Bcnt ;

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) ;
    }
}
bool solve(){
    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 ;
}
int main(){
    int a ,b ,c ;
    while(scanf("%d%d",&N,&M) == 2){
        memset(be,  -1,sizeof(be));
        memset(fa, -1, sizeof(fa));
        for(int i=1;i<=N;i++){
            scanf("%d%d%d",&a1[i],&a2[0][i],&a2[1][i]);
            fa[ a1[i] ] = a1[i] ;
            fa[ a2[0][i] ] = a2[0][i] ;
            fa[ a2[1][i] ] = a2[0][i] ;
            nn[ a1[i] ] = i ;
            nn[ a2[0][i] ] = i + N ;
        }
        memset(Gr,-1, sizeof(Gr));  Gc = 0 ;
        for(int i=1;i<=M;i++){
            scanf("%d%d",&a,&b);
            int aa = fa[a] ;
            int bb = fa[b] ;
            int na = nn[aa] ;
            int nb = nn[bb] ;
            int oa ,ob ;
            if(na > N)  oa = na - N ;
            else    oa = na + N ;
            if(nb > N)  ob = nb - N ;
            else    ob = nb + N ;
            add(na , ob);
            add(nb , oa);
        }
        if( solve() )   printf("yes\n");
        else            printf("no\n");
    }
    return 0 ;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值