BZOJ 2582 : Bovine Alliance DFS
2582: [Usaco2012Jan]Bovine Alliance
Description
Input
* Line 1: Two space-separated integers N and M
* Lines 2..1+M: Line i+1 describes the ith trail. Each line contains two space-separated integers u_i and v_i (1 <= u_i, v_i <= N, u_i != v_i) describing the pair of farms connected by the trail. Note that there can be two trails between the same pair of farms.
Output
* Line 1: A single line containing the number of assignments of trails to farms, taken modulo 1,000,000,007. If no assignment satisfies the above conditions output 0.
Sample Input
1 2
3 2
4 5
4 5
Sample Output
思路 :
本题理清思路考虑就好了,因为集合只存在两种情况 即 只有一个点,或者 一个点配一个边, 那么只需要对每个联通块分情况考虑 。若V<E 那么肯定有边不在集合里,直接输出0
若V==E,则只要确定该联通块和哪个点分组,整个联通块的分组情况就确定了,而一条边只会有两种分组情况,故对答案的贡献为2, 如果V==E+1 则联通块是个树,那么任选一个点为根,都有一种方案,故对答案的贡献为V。
而具体维护的方法我们可以采用并查集(Tarjan肯定也是可以的,但我没有写)来维护一下联通块的信息,最后把每个联通块的ANS乘到一起就是答案,别忘了mod1e9+7哦!
下面附上代码
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int p = 1e9+7; int fa[110000],psiz[110000],esiz[110000]; long long ans; struct node { int s,t; }e[110000]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int main() { int n, m, s, t; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) fa[i]=i,psiz[i]=1; for(int i=1;i<=m;i++) { scanf("%d%d",&s,&t); int dx=find(s),dy=find(t); if(dx!=dy) fa[dx]=dy, esiz[dy]+=esiz[dx]+1, psiz[dy]+=psiz[dx]; else esiz[dx]++; } ans=1; for(int i=1;i<=n;i++) if(fa[i]==i) if(psiz[i]==esiz[i]+1) (ans*=psiz[i])%=p; else if(psiz[i]==esiz[i]) (ans*=2)%=p; else { puts("0"); return 0; } printf("%lld\n",ans%p); }
欢迎来原Blog看看 >原文链接<