//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;
}
CF571C-CNF 2
最新推荐文章于 2024-08-12 15:53:23 发布