题意:给n个点m条边的图,每条边有一个权重,表示两端点的权值和,每个点的权值为0或1,问所有点的最小权重。
分析:类似2-SAT的方法对全图染色,注意每个点染两次,取最小值。
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include <unordered_map>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define MAXN 400005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
vector<pii> G[MAXN];
int ans,n,m,col[MAXN],jud[MAXN];
void GG()
{
cout<<"impossible"<<endl;
exit(0);
}
int dfs(int u,int color,int time)
{
int ans = color;
jud[u] = time;
col[u] = color;
for(pii v : G[u])
if(!v.second)
{
if(color) return n+1;
if(jud[v.first] != time) ans += dfs(v.first,0,time);
else
if(col[v.first]) return n+1;
}
else
if(v.second == 1)
{
if(jud[v.first] != time) ans += dfs(v.first,color^1,time);
else
if((col[v.first] && color) || (!color && !col[v.first])) return n+1;
}
else
{
if(!color) return n+1;
if(jud[v.first] != time) ans += dfs(v.first,1,time);
else
if(!col[v.first]) return n+1;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
G[x].push_back(make_pair(y,z));
G[y].push_back(make_pair(x,z));
}
for(int i = 1;i <= n;i++)
if(!jud[i]) ans += min(dfs(i,0,1),dfs(i,1,2));
if(ans > n) GG();
cout<<ans<<endl;
}