#1467 : 2-SAT·hihoCoder音乐节

描述

hihoCoder音乐节由hihoCoder赞助商大力主办,邀请了众多嘉宾和知名乐队参与演出。

音乐会分为上午、下午两场进行,主办方指定了n首歌让乐队进行演唱。每首歌只会被演唱一次,要么在上午要么在下午。

参加音乐会的嘉宾们对于歌曲的演唱时间有一些要求。具体来说,每位嘉宾会指定两首歌曲的演唱时间(上午或者下午)。如果最后实际的演出安排中,两首歌都没有达到嘉宾的要求,那么嘉宾就会对音乐节不滿意。如嘉宾A的要求是上午《我的滑板鞋》和下午《忐忑》,而最后的演出中上午没有《我的滑板鞋》只有《忐忑》,下午没有《忐忑》只有《我的滑板鞋》,那么嘉宾A是不满意的。

音乐节主办方自然希望使所有嘉宾满意,但主办方后来发现有可能不存在一种歌曲的安排方案满足所有嘉宾,所以他们希望你判断一下这种情况是否会发生。

解题方法提示

输入

输入第一行包含一个数字 K,代表K组数据。(K≤50)

对于每一组数据,第一行包含两个非负整数n和m(n≤100,m≤1000),代表有n首歌和m位嘉宾。

为了方便我们给予歌编号,编号分别从1 到n。接下的m行,每行都代表对应的嘉宾的喜好由一个英文字母(m或h)跟一个数字代表,如m1 代表这个评审喜欢第1首歌上午进行,而h2代表这个评审员喜欢第2首歌下午进行。

输出

对于每一组数据,输出一行,如果能满足所有嘉宾的情况,输出GOOD;否则输出BAD。

样例输入
2
3 4
m3 h1
m1 m2
h1 h3
h3 m2
2 4
h1 m2
m2 m1
h1 h2
m1 h2
样例输出
GOOD
BAD

2-sat问题,好恶心,当时学习的时候没怎么做题。

做了好久。终于a了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=550+10;
int n,m;
int dfs_clock;
int scc_cnt;
vector<int> G[maxn];
int pre[maxn];
int low[maxn];
int sccno[maxn];
stack<int> S;
vector<int> F[maxn];
void dfs(int u)
{
    pre[u]=low[u]=++dfs_clock;
    S.push(u);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!pre[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v])
        {
            low[u]=min(low[u],pre[v]);
        }
    }
    if(low[u] == pre[u])
    {
        scc_cnt++;
        while(true)
        {
            int x=S.top(); S.pop();
            sccno[x]=scc_cnt;
            //F[scc_cnt].push_back(x);
            if(x==u) break;
        }
    }
}


void find_scc()
{
    scc_cnt=dfs_clock=0;
    memset(sccno,0,sizeof(sccno));
    memset(pre,0,sizeof(pre));
    memset(low,0,sizeof(low));
    for(int i=1;i<=2*n;i++)
    {
       if(!pre[i])dfs(i);
    }
}
int q(char a[])
{
    int l=strlen(a);
    int sum=0;
    for(int i=1;i<l;i++)
    {
        sum=sum*10+a[i]-'0';
    }
    //cout<<sum<<endl;
    return sum;

}
/*
    void add_clause(int x,int xval,int y,int yval)
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }
    */
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=2*n;i++) G[i].clear();
        //for(int i=1;i<=2*n;i++) F[i].clear();
        int u,v;
        char s[6],x[6];
        while(m--)
        {
            scanf("%s%s",s,x);
            u=q(s);
            v=q(x);
            int un=u+n;
            int vn=v+n;
            if(s[0]=='h')swap(u,un);
            if(x[0]=='h')swap(v,vn);
            //cout<<u<<" "<<v<<endl;
            G[vn].push_back(u);
            G[un].push_back(v);
        }
        find_scc();

        int sum=0;
        /*
        for(int i=1;i<=scc_cnt;i++)
        {
            for(int j=0;j<F[i].size();j++)
            {
                printf("%d ",F[i][j]);
            }
            printf("\n");
        }
        */
        for(int i=1;i<=n;i++)
        {
            if(sccno[i]==sccno[i+n])
            {
                sum=1;
            }
        }
        if(sum)printf("BAD\n");
        else printf("GOOD\n");
    }
   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值