题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=158908
题意:给一些点和一些边。边的权值可为0,1,2,分别表示边的两个结点上取0个、1个、2个。存在矛盾的答案,即输出impossible。问合法情况下,最少取多少个点。
思路:
在输入过程中初始化use数组,-1为不能使用,1为使用。此时有矛盾判断。
全部输入完毕后,利用深搜和邻接表搜索每一个use不为0的机场,即已经确定关系的机场,将他们标记。此时又矛盾判断。
统计所有已经确定的点中必须使用的个数。
此时,剩余所有点为不确定点。
对每一个点进行深搜。设第一个点的值为1,按照之前的标记方法标记,因为深搜可以标记该点所在的最大连通图,所以此时答案只要加上得到的连通图中分别标记为0和1的点数目的最小值。再继续往下搜时,搜到的点与前面点为两个不连通的点。所以01标记不会相互影响。此时依然有矛盾判断
这应该也是二分图染色的思路。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <vector>
using namespace std;
int const MAXN = 200000+5;
vector<int>lin[MAXN];
int use[MAXN],n,m,flag,ff;
typedef pair<int,int> pp;
void init()
{
flag = 0;
memset(use,0,sizeof(use));
for(int i=1;i<=n; i++)
lin[i].clear();
int s,e,val;
while(m--){
scanf("%d%d%d",&s,&e,&val);
val--;
if(val){
if(use[s]==0) use[s] = val;
else if(use[s]==-val){flag=1; use[s]=val;}
if(use[e]==0) use[e] = val;
else if(use[e]==-val){flag=1; use[e]=val;}
}
else{
lin[s].push_back(e);
lin[e].push_back(s);
}
}
}
void dfs1(int u,int father,int val)
{
for(int i=0; i<lin[u].size(); i++){
int temp = lin[u][i];
if(temp == father || use[temp]==-val)
continue;
if(use[temp]==val){
flag = 1;
return;
}
use[temp] = -val;
dfs1(temp,u,-val);
}
}
pp dfs2(int u,int father,int val)
{
pp res = make_pair(0,0);
if(val==1) res.first++;
else res.second++;
for(int i=0; i<lin[u].size(); i++){
if(lin[u][i] ==father || use[lin[u][i]]==-val)
continue;
// printf("i = %d,lin = %d,use of lin = %d\n",u,lin[u][i],use[lin[u][i]]);
if(use[lin[u][i]]==val){
flag = 1;
return res;
}
use[lin[u][i]] = -val;
pp temp = dfs2(lin[u][i],u,-val);
res.first += temp.first;
res.second += temp.second;
}
return res;
}
void solve()
{
if(flag){
printf("impossible\n");
return;
}
for(int i=1; i<=n; i++){
if(use[i])
dfs1(i,i,use[i]);
if(flag){
printf("impossible\n");
return;
}
}
ff = 0;
for(int i=1; i<=n; i++)
if(use[i]==1)
ff++;
for(int i=1; i<=n; i++){
if(use[i])
continue;
use[i] = 1;
pp tt = dfs2(i,i,1);
if(flag)
break;
ff += min(tt.first,tt.second);
}
if(flag)
printf("impossible\n");
else
printf("%d\n",ff);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(int i=1; i<=n; i++){
// printf("i = %d ",i);
// for(int j=0; j<lin[i].size(); j++)
// printf("%d ",lin[i][j]);
// printf("\n");
}
solve();
}
return 0;
}
/*
4 3
1 2 1
2 3 1
1 3 1
*/