CF571C-CNF 2

来源:互联网 发布:虚拟服务器和端口转发 编辑:程序博客网 时间:2024/06/07 12:57
//CF571C-CNF 2//遇上了一个奇怪的二分匹配算法//x集合是变量,y集合是析取式//因为一个变量最多有两条边,如果变量的两条边都是同一性质,都是本身,或都是反变量,变量的值可直接得出//剩下的就是只有一条边,或两条性质不同的边,性质不同只能选一个,所以就变成了二分图的最大匹配问题//二分图匹配的匈牙利算法和Hopcroft-Krap算法都会T//看到一个歪果仁的匹配算法,不明觉厉,求路过的大牛指点QAQ,这是个啥算法#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<vector>using namespace::std;const int M=200010;vector<int>var[2*M],edge[2*M];bool ans[M],equ[M],vis[M],found;int line[M],l[M];void dfs(int u){    for(int i=0;i<edge[u].size();i++){        int v=edge[u][i];        if(!vis[v]){            vis[v]=true;            if(line[v]!=-1)dfs(line[v]);            else found =true;            if(found){                line[v]=u;                return;            }        }    }}int Max_match(int nx,int ny){    for(int i=1;i<=ny;i++)line[i]=-1;    for(int i=1;i<=nx;i++)l[i]=i;    int nlist=nx,old=0;    do{        old=nlist;        for(int i=1;i<=ny;i++)vis[i]=false;        for(int i=nlist;i>=1;i--){            found=false;            dfs(l[i]);            if(found){                l[i]=l[nlist];                nlist--;            }        }    }while(old!=nlist);    return nx-nlist;}int main(){    int n,m,k,x;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%d",&k);        for(int j=0;j<k;j++){            scanf("%d",&x);            if(x>0)var[x].push_back(i);            else var[m-x].push_back(i);        }    }    for(int i=1;i<=m;i++){        if(var[i].size()==2){            ans[i]=true;            equ[var[i][0]]=equ[var[i][1]]=true;        }        if(var[i+m].size()==2){            equ[var[i+m][0]]=equ[var[i+m][1]]=true;        }    }    int num=0;    for(int i=1;i<=n;i++)if(equ[i]==true)num++;    for(int i=1;i<=m;i++){        for(int j=0;j<var[i].size();j++){            if(!equ[var[i][j]])edge[i].push_back(var[i][j]);        }        for(int j=0;j<var[i+m].size();j++){            if(!equ[var[i+m][j]])edge[i].push_back(var[i+m][j]);        }    }    int mat=Max_match(m,n);    if(mat!=n-num){        printf("NO\n");    }    else{        for(int i=1;i<=n;i++){            if(line[i]!=-1){                int u=line[i];                if(var[u].size()>0&&var[u][0]==i)ans[u]=true;            }        }        printf("YES\n");        for(int i=1;i<=m;i++)            printf("%d",ans[i]?1:0);        printf("\n");    }    return 0;}

0 0