hiho一下 第133周 2-SAT·hihoCoder音乐节

本文详细介绍了2-SAT算法在解决hihoCoder音乐节歌曲播放时间冲突问题的应用。通过将问题转化为图论中的强连通分量问题,利用Tarjan算法进行求解,实现了对歌曲播放时间安排的有效判断。

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


https://hihocoder.com/contest/hiho133/problem/1

题目1 : 2-SAT·hihoCoder音乐节


步骤:

上午为真 ,下午为假

把点分成2*X,2*X+1

构图方法: 

对于  a or b 的条件

转换成 ¬a->b AND ¬b->a

就是分别连两条边 ¬a->b , ¬b->a


最后对构出的图,跑强连通分量,判断 同一个点的真假如果在同一个强联通分量里,则矛盾。(即推出一首歌既要在上午播出又要在下午播出,即真假同时成立)


为什么只跑个强连通分量(tarjan)即可呢,因为原图中每一条边(a->b)的意义是 a可以推导出b

如果一个点拆成真假2x,2x+1两个点后在一个强联通里,则我们必须选一个值,不管选哪个,都会推导到真假同时成立,显然矛盾,反之,如果整个图所有拆出的点两两都不在一个强联通分量,则必然可以找出一组解.


#include<bits/stdc++.h>
using namespace std;
const int maxn=105*2;
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
vector<int> mp[maxn] ;
stack<int>st;

void add_edge(int x,bool xval,int y,bool yval)
{
    x=x*2+xval;
    y=y*2+yval;
    mp[x^1].push_back(y);
    mp[y^1].push_back(x);
}

void dfs(int u)
{
    pre[u]=lowlink[u]=++dfs_clock;
    st.push(u);
    for (int i=0; i<mp[u].size(); i++)
    {
        int v=mp[u][i];
        if (!pre[v])
        {
            dfs(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        }
        else if (!sccno[v])
            lowlink[u]=min(lowlink[u],pre[v]);
    }
    if (lowlink[u]==pre[u])
    {
        scc_cnt++;
        for (;;)
        {
            int x=st.top();
            st.pop();
            sccno[x]=scc_cnt;
            if (x==u)   break;
        }
    }
}
void find_scc(int n)
{
    scc_cnt=dfs_clock=0;
    memset(pre,0,sizeof pre);
    memset(sccno,0,sizeof sccno);
    for (int i=0; i<n; i++)
        if (!pre[i]) dfs(i);
}
int main()
{

    int t;
    cin>>t;
    char A[100],B[100];
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n*2;i++)
        mp[i].clear();
        getchar();
        for(int i=1; i<=m; i++)
        {
            scanf("%s %s",A,B);
            int numa=0,numb=0,lena=strlen(A),lenb=strlen(B);
            for(int j=1;j<lena;j++) numa=numa*10+A[j]-'0';
            for(int j=1;j<lenb;j++) numb=numb*10+B[j]-'0';
            numa--,numb--;
            if (A[0]=='m'&&B[0]=='m')      add_edge(numa,1,numb,1);
            if (A[0]=='m'&&B[0]=='h')      add_edge(numa,1,numb,0);
            if (A[0]=='h'&&B[0]=='h')      add_edge(numa,0,numb,0);
            if (A[0]=='h'&&B[0]=='m')      add_edge(numa,0,numb,1);
        }
        find_scc(2*n);
        int flag=1;
        for(int i=0;i<2*n;i+=2)
            if (sccno[i]==sccno[i+1]) flag=0;
            if (flag)
        printf("GOOD\n");
        else
        printf("BAD\n");

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值