There are many anime that are about "love triangles": Alice loves Bob, and Charlie loves Bob as well, but Alice hates Charlie. You are thinking about an anime which has n characters. The characters are labeled from 1 to n. Every pair of two characters can either mutually love each other or mutually hate each other (there is no neutral state).
You hate love triangles (A-B are in love and B-C are in love, but A-C hate each other), and you also hate it when nobody is in love. So, considering any three characters, you will be happy if exactly one pair is in love (A and B love each other, and C hates both A and B), or if all three pairs are in love (A loves B, B loves C, C loves A).
You are given a list of m known relationships in the anime. You know for sure that certain pairs love each other, and certain pairs hate each other. You're wondering how many ways you can fill in the remaining relationships so you are happy with every triangle. Two ways are considered different if two characters are in love in one way but hate each other in the other. Print this count modulo1 000 000 007.
The first line of input will contain two integers n, m (3 ≤ n ≤ 100 000, 0 ≤ m ≤ 100 000).
The next m lines will contain the description of the known relationships. The i-th line will contain three integers ai, bi, ci. If ci is 1, then aiand bi are in love, otherwise, they hate each other (1 ≤ ai, bi ≤ n, ai ≠ bi, ).
Each pair of people will be described no more than once.
Print a single integer equal to the number of ways to fill in the remaining pairs so that you are happy with every triangle modulo1 000 000 007.
3 0
4
4 4 1 2 1 2 3 1 3 4 0 4 1 0
1
4 4 1 2 1 2 3 1 3 4 0 4 1 1
0
解题思路:这道题目还是花了一定的时间的,要是比赛时肯定是做不出来的。我们需要明确一个有用的结论是从图中任意一个顶点出发向其余n-1个点之间的连边确定了,则这完全图的所有边便可以确定下来。假如从顶点1向其余n-1个顶点连边,则1->u,1->v这两条边确定了,则u->v确定了,考虑符合题意的所有条件很容易发现情况是唯一。题目中已经给了我们一些边u->v之间的关系,这样1->u,1->v的异同是可以确定的。将边的情况转移到点上,便可以将问题转化成,顶点的黑白染色问题,给定一些顶点对之间颜色的关系,让我们对整个图进行黑白染色的方案数,显然这个方案数是2^(互不存在关系集合的个数-1),减1是因为和顶点1关联的那个集合的对应的原图中边的类型是能够唯一确定,而剩下的集合便是2种方案(黑白色颠倒一下即可)。对于这些不相交集合我们统计可以采用两种方法,一种方法直接利用dfs进行黑白染色,二是采用并查集(顶点间颜色之间的关系,所以得是种类并查集),然后我们便可以计算最终的结果。
程序代码:两种方法计算
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <string> #include <vector> #include <deque> #include <map> #include <set> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 100010; const ll mod = 1000000007; struct Edge { int u, v, r, next; Edge() { } Edge(int t_u, int t_v, int t_r, int t_next) : u(t_u), v(t_v), r(t_r), next(t_next) { } }edges[2*maxn]; int head[maxn], edge_sum; void init_graph() { edge_sum = 0; memset(head, -1, sizeof(head)); } void add_edge(int u, int v, int r) { edges[edge_sum].u = u; edges[edge_sum].v = v; edges[edge_sum].r = r; edges[edge_sum].next = head[u]; head[u] = edge_sum++; edges[edge_sum].u = v; edges[edge_sum].v = u; edges[edge_sum].r = r; edges[edge_sum].next = head[v]; head[v] = edge_sum++; } int color[maxn]; bool dfs(int u, int c) { color[u] = c; for(int i = head[u]; i != -1; i = edges[i].next) { int v = edges[i].v, r = edges[i].r; if(color[v] == -1) { if(!dfs(v, c^r)) { return false; } } else { if((color[u]^color[v]^r) != 0) { return false; } } } return true; } int main() { //freopen("aa.in", "r", stdin); ll ans = 1; int n, m; int u, v, r; scanf("%d %d", &n, &m); init_graph(); for(int i = 0; i < m; ++i) { scanf("%d %d %d", &u, &v, &r); add_edge(u, v, 1 - r); } memset(color, -1, sizeof(color)); for(int i = 1; i <= n; ++i) { if(color[i] == -1) { if(dfs(i, 0)) { if(i != 1) { ans = ans * 2 % mod; } } else { ans = 0; break; } } } cout << ans << endl; return 0; } int parent[maxn]; int color[maxn]; void init_set() { memset(parent, -1, sizeof(parent)); memset(color, 0, sizeof(color)); } int find_set(int u) { if(parent[u] < 0) return u; int t = parent[u]; parent[u] = find_set(parent[u]); color[u] = color[u]^color[t]; return parent[u]; } void union_set(int u, int v, int r) { int r1 = find_set(u); int r2 = find_set(v); parent[r2] += parent[r1]; parent[r1] = r2; color[r1] = (color[u]^color[v]^r); return ; } int main() { //freopen("aa.in", "r", stdin); int n, m, u, v, r; ll ans = 1; int tot; init_set(); scanf("%d %d", &n, &m); tot = n - 1; for(int i = 0; i < m; ++i) { scanf("%d %d %d", &u, &v, &r); r = 1 - r; if(ans == 0) continue; int r1 = find_set(u); int r2 = find_set(v); if(r1 != r2) { tot--; union_set(u, v, r); } else { if((color[u]^color[v]^r) != 0) { ans = 0; } } } for(int i = 1; i <= tot; ++i) { ans = ans * 2 % mod; } cout << ans << endl; return 0; }