HDU1824-Let's go home

本文介绍了一种基于2-sat算法解决队伍分配问题的方法。通过将每个队伍拆分为两个小组并构建图,利用Tarjan算法寻找强连通分量来判断是否能够合理分配。文章详细解释了算法流程,并附带完整的C++实现代码。

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


题解:
裸的2sat2−sat
把每个队分成两组,第ii个队的两个小分队编号为2i1i2i∗2;然后根据2sat2−sat建边,判断强联通即可即判断2i12∗i−1i2i∗2是否在同一个强联通分量。
CodeCode:

#include<bits/stdc++.h>
#define N 10005
using namespace std;
int tot,sum,deep,dfn[N],cnt[N],a[N],low[N],head[N],top,flag[N],color[N];
struct node
{
    int vet,next;
}edge[N];
void add(int u,int v)
{
    edge[++tot].vet=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++deep;
    a[++top]=u;flag[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].vet;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else
        if(flag[v])
            low[u]=min(low[u],low[v]);
    }
    if(dfn[u]==low[u])
    {
        color[u]=++sum;
        flag[u]=false;
        while(a[top]!=u)
        {
            flag[a[top]]=false;
            color[a[top--]]=sum;
        }
        top--;
    }
}
int main()
{
    int T,m;
    while(~scanf("%d%d",&T,&m))
    {
        for(int i=1;i<=T;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            cnt[a]=2*i-1;
            cnt[b]=cnt[c]=2*i;
        }
        tot=0;
        memset(head,-1,sizeof(head));
        while(m--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if(cnt[a]!=cnt[b])
                if(cnt[a]%2==1&&cnt[b]%2==1)
                {
                    add(cnt[a],cnt[b]+1);
                    add(cnt[b],cnt[a]+1);
                }else
                if(cnt[a]%2==0&&cnt[b]%2==0)
                {
                    add(cnt[a],cnt[b]-1);
                    add(cnt[b],cnt[a]-1);
                }else
                if(cnt[a]%2==0&&cnt[b]%2==1)
                {
                    add(cnt[a],cnt[b]+1);
                    add(cnt[b],cnt[a]-1);
                }else
                if(cnt[a]&1&&cnt[b]%2==0)
                {
                    add(cnt[a],cnt[b]-1);
                    add(cnt[b],cnt[a]+1);
                }
        }
        memset(dfn,0,sizeof(dfn));
        memset(flag,false,sizeof(flag));
        sum=deep=top=0;
        for(int i=1;i<=2*T;i++)
            if(!dfn[i])tarjan(i);
        int ans=0;
        for(int i=1;i<=T;i++)
            if(color[i*2-1]==color[i*2])
            {
                ans++;
                break;
            }
        if(ans)puts("no");else
            puts("yes");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackflyDC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值