http://codeforces.com/gym/100502/attachments
题意:有n个地点,m条边,每条边有一个边权,0代表两个顶点都染成白色,2代表两个顶点都染成黑色,1代表两个顶点可能尚未染色,但是之后必须一个染成白色一个染成黑色。问是否有可能让这个图成功染色,如果可能输出染成黑色的最少顶点数。
思路:一开始0和2的边是确定的,直接染,如果有矛盾直接false。然后利用边权为1的边建图。先考虑如果图中的某个点已经染色了,那么直接DFS染色,然后这个阶段出现黑色的点是确定的(因为必须染成这个颜色),如果出现矛盾就返回。
再考虑如果图中没有点染色,这个时候随便染一种颜色,用两个计数器a和b,代表这个阶段染成白色的点和黑色的点的数目,这个对答案的贡献为min(a, b),因为点都是不确定的,所以染成白和染成黑都是一样的,所以可以互换,然后出现矛盾就返回。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 200010 4 struct Edge { 5 int v, nxt; 6 } edge[N*2]; 7 int vis[N], head[N], tot, col[N], a, b, ans; 8 9 void Add(int u, int v) { 10 edge[tot] = (Edge) {v, head[u]}; head[u] = tot++; 11 edge[tot] = (Edge) {u, head[v]}; head[v] = tot++; 12 } 13 14 bool DFS(int u, int c, int kind) { 15 if(kind) { 16 if(col[u] == 1) b++; else a++; 17 } else { 18 if(col[u] == 1) ans++; 19 } 20 for(int i = head[u]; ~i; i = edge[i].nxt) { 21 int v = edge[i].v; 22 if(col[v] == c) return false; 23 if(!vis[v]) { vis[v] = 1; if(col[v] == 0) col[v] = -c; if(!DFS(v, col[v], kind)) return false; } 24 } 25 return true; 26 } 27 28 int main() { 29 int n, m; 30 scanf("%d%d", &n, &m); 31 memset(head, -1, sizeof(head)); 32 bool flag = 1; 33 for(int i = 0; i < m; i++) { 34 int u, v, k; 35 scanf("%d%d%d", &u, &v, &k); 36 if(k == 2) { 37 if(col[u] == -1 || col[v] == -1) flag = 0; 38 col[u] = col[v] = 1; 39 } else if(k == 0) { 40 if(col[u] == 1 || col[v] == 1) flag = 0; 41 col[u] = col[v] = -1; 42 } else Add(u, v); 43 } 44 for(int i = 1; i <= n; i++) 45 if(!vis[i] && col[i]) { vis[i] = 1; if(!DFS(i, col[i], 0)) flag = 0; } 46 for(int i = 1; i <= n; i++) { 47 if(vis[i]) continue; 48 a = 0; b = 0; vis[i] = 1; col[i] = 1; 49 if(!DFS(i, 1, 1)) flag = 0; 50 ans += a > b ? b : a; 51 } 52 if(!flag) puts("impossible"); 53 else printf("%d ", ans); 54 return 0; 55 }