题目链接:
题目大意:
给出n个点,要求构造合法的完全图,已经给出了一些边,边有红边和蓝边,其中任意三个点,连成的边合法的组合有红红红,红蓝蓝
问符合要求的完全图的数量
题目分析:
首先我们考虑三个点,可能存在的合法组合是红红红,红蓝蓝,那么如果给出其中一条边(x,y)是红,那么可以断定x,y到另外一点的颜色一定相同;
如果是蓝色,那么,x和y到另外一点的颜色一定不同,因此对于有边相连的一堆点,我们称为一个连通块,那么对于这个连通块当中点看成是和其中某一点的为dfs的起点,那么只要确定它到其他点的颜色,因为两条边颜色确定后第三条边颜色是一定的,所以就只能得到一个完全图,然而如果题中给出了x,y有边,那么就可以直接给出(1,x),(1,y)的颜色关系,(建设dfs起点为1),那么在dfs中,(1,1)一定是红色,那么根据颜色关系,可以对其他的点进行染色,存在满足所有关系的那么构成一个连通块,没有的话整个题就无解。然后分成连通块之后,对于每个连通块,只要和其他连通块建立一条边,因为两边可以确定第三边,所以其他的边都变成确定的。所以最后就是连通块个数k,结果为2^k
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#define MAX 100007
using namespace std;
vector< pair<int,int> > e[MAX];
int vis[MAX];
const int mod = 1e9+7;
int ans;
void dfs ( int x )
{
for ( int i = 0 ; i < e[x].size(); i++ )
{
int v = e[x][i].first;
int t = e[x][i].second;
if ( vis[v] == -1 )
{
if ( t == 1 )
vis[v] = vis[x];
else
vis[v] = 1 - vis[x];
dfs ( v );
}
if ( t == 1 )
{
if ( vis[v] != vis[x] )
ans = 0;
}
else
{
if ( vis[v] == vis[x] )
ans = 0;
}
}
}
int main ( )
{
int n,m,a,b,c;
while ( ~scanf ( "%d%d" , &n , &m ) )
{
for ( int i = 0 ; i < m ; i++ )
{
scanf ( "%d%d%d" , &a , &b , &c );
e[a].push_back ( make_pair(b,c) );
e[b].push_back ( make_pair(a,c) );
}
ans = (mod+1)/2;
memset ( vis , -1 , sizeof ( vis ) );
for ( int i = 1 ; i <= n ; i++ )
{
if ( vis[i] == -1 )
{
ans = (ans+ans)%mod;
vis[i] = 0;
dfs (i);
}
}
printf ( "%d\n" , ans );
}
}