BZOJ 2582: [Usaco2012Jan]Bovine Alliance

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2582

解:这道题是老师给我们拿来当做考试的,结果考的时候,我在判断无向图联通块时,满脑子tarjan。。。完全忘了并查集。。。最后用了深搜,然而竟然92分??

这道题就是用并查集判断出分别的联通块,然后在一个联通块中,

if (u==e) 方案数为u(点的数量)

if (u==e-1) 方案数为 2

if (u<e) 无解。。。

然后乘起来就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define INF 1000000007
using namespace std;
int n,m,u,v,nume[200000],nump[200000],father[200000];
vector<int>edge[200000];
int findf(int x)
{
  if (x==father[x]) return x;
  else 
  {
      father[x]=findf(father[x]);
      return father[x];
  }
}
int main()
{
  scanf("%d%d",&n,&m);
  for (int i=1;i<=m;i++)
  {
      scanf("%d%d",&u,&v);
      edge[u].push_back(v);
  }
  for (int i=1;i<=n;i++) father[i]=i,nump[i]=1;
  for (int i=1;i<=n;i++)
   for (int j=0;j<edge[i].size();j++)
   {
        int x=findf(i); int y=findf(edge[i][j]);
        if (x!=y) { father[y]=i; nump[x]+=nump[y];nump[y]=0;nume[x]+=nume[y];}
        nume[x]++;
   }
  long long ans=1;
  for (int i=1;i<=n;i++) int now=findf(i);
  for (int i=1;i<=n;i++) 
  if (nump[i])
  {
      if (nump[i]<nume[i]) 
      {
        printf("0
");
      return 0;    
    }
    else if (nump[i]>nume[i]) ans=(ans*nump[i])%INF;
    else ans=(ans*2)%INF;
  }
  printf("%lld
",ans);
  return 0;
} 
原文地址:https://www.cnblogs.com/2014nhc/p/6660390.html