题意:n个白点.有m个条件(u,v,x).
(u,v,x) x=0表示u,v两点都不能变为黑色.
(u,v,x) x=1表示u,v两点正好有一点要涂成为黑色.
(u,v,x) x=2表示u,v两点都要涂成黑色.
n,m<=2e5. 问最少要把多少个点涂成黑色才能满足m个条件.无解输出-1.
建图:先把所有(u,v,x=1)的 (u,v)连接一条边.
(u,v,x=2)的点mk标记为true ,(u,v,x==0)的点ban标记为true.
把mk[u]==1的点染成黑色,因为u-v正好只能有一个点为黑,那么它相邻的点v只能染成白色.
ban[u]==1的点只能为白色.因为u-v要有一个点为黑色.所以它相邻的点v要染成白色.
做好二分图染色后,已经满足了其中两类条件
剩下联通分量中的点显然ban[i],mk[i]都没有被标记.可以任意染色.
因为确定一个点颜色后整个联通分量的黑点也就确定 取其中最小值即可.
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,col[N];
int cnt_a,cnt_b,res=0;
bool mk[N],ban[N],flag;
vector<int> e[N];
void dfs(int u,int c,int op){
if(col[u]!=-1){
if(col[u]!=c) flag=false;
return;
}
col[u]=c;
if(col[u]==1){
cnt_a++;
if(op==0) res++;
if(ban[u]) flag=false;
}
else{
cnt_b++;
if(mk[u]) flag=false;
}
for(int i=0;i<e[u].size();i++){
int v=e[u][i];
dfs(v,1-c,op);
}
}
int main(){
cin>>n>>m;
int u,v,x;
while(m--){
cin>>u>>v>>x;
if(x==0) ban[u]=ban[v]=true;
else if(x==2) mk[u]=mk[v]=true;
else{
e[u].push_back(v);
e[v].push_back(u);
}
}
flag=true;
memset(col,-1,sizeof(col));
for(int i=1;i<=n;i++)
{
if(mk[i]&&col[i]==-1) dfs(i,1,0);
if(ban[i]&&col[i]==-1) dfs(i,0,0);
}
for(int i=1;i<=n;i++){
if(col[i]!=-1) continue;
cnt_a=cnt_b=0;
dfs(i,1,1);
res+=min(cnt_a,cnt_b);
}
if(flag==false) cout<<"impossible"<<'\n';
else cout<<res<<'\n';
return 0;
}