 /**//*
题意:给出一个有向图,现可以加边,问有多少种方案使得图上的每个点在且仅在一个环中
而且除了环边外没有多余的边(不用加边也算一种方案)

http://www.hhanger.com/blog/?p=438
这题首先要判断是否已经有多余的边了,如果有某些点的入度或者出度大于等于2了,
则肯定无解。否则的话,整个图可以分成x个独立点和y条有头尾的弧(环可以直接扔掉
),需要互相或者自己相接成环,但是不能有长度为1的环。

利用组合数加上错排公式;
分成两部分,前面是独立点,后面是弧
枚举多少条弧加到独立点中一起组成环,剩下的弧自成环
组成环,就是错排公式了
因为错排了,像置换那样子,每个点对应错排的位置就是要连边的位置了
答案就是 ∑C[left][i-numOfOne]*D[i]
*/
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>

using namespace std;

const int MOD = 10000007;

vector<int>E[110];
int in[110];
long long D[110] , C[110][110];

void init()
  {
C[0][0] = 1;
for(int i = 1 ; i <= 100 ; i++)
 {
C[i][0] = C[i][i] = 1;
for(int j = 1; j < i; j++)
 {
C[i][j] = (C[i-1][j] + C[i-1][j-1] )%MOD;
}
}
D[0] = 1;
D[1] = 0;
for(int i = 2; i <= 100; i++)
 {
D[i] = (i-1)*(D[i-1] + D[i-2])%MOD;
}
}

int dfs(int u)
  {
if(E[u].size()==0)return 1;
return 1+dfs(E[u][0]);
}

int main()
  {
//freopen("in","r",stdin);

init();
int n;
char str[110];
while(scanf("%d",&n) , n )
 {
memset(in,0,sizeof(in));
for(int i = 1 ; i<=n ; i++)
 {
scanf("%s",str);
E[i].clear();
for(int j = 1 ; j <= n ; j++)
 {
if(str[j-1]=='Y')
 {
E[i].push_back(j);
in[j]++;
}
}
}
bool flag = true;
for(int i = 1; i<=n && flag ;i++)
 {
if(E[i].size()>=2 || in[i]>=2)flag = false;
}
if(!flag)puts("0");
else
 {
int store[110],tot = 0;
for(int i = 1 ; i <= n ; i++)
 {
if(in[i] == 0) store[tot++] = dfs(i);
}
sort(store,store+tot);
int numOfOne = upper_bound(store,store+tot,1)-store;
int left = tot - numOfOne;
long long ans = 0;
for(int i = numOfOne ; i <= tot ;i++)
 {
ans = (ans + C[left][i-numOfOne]*D[i] ) %MOD;
}
printf("%lld\n",ans);
}
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|