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

来源:互联网 发布:大革命1060设置优化 编辑:程序博客网 时间:2024/05/29 03:41


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


0 0
原创粉丝点击