/**//* 题意:给出一个有向图,现可以加边,问有多少种方案使得图上的每个点在且仅在一个环中 而且除了环边外没有多余的边(不用加边也算一种方案)
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
搜索
最新评论
|
|