题意:
给定n个点 以及有向边的矩阵。
加一些有向边使得 每个点 入度=出度= 1; 的方法数 (原意是每个点只存在于一个环 (一个环至少2个点
显然图中的点我们分为4种 (入度,出度) (0,0) (0,1) (1,0) (1,1) (若有其他类的点则图不合法,直接输出0)
而且 Num(0,1) == Num(1,0)
因为这种点只会在链两端各产生一个
剩下的则是孤立点 (0,0) (因为(1,1)点是在链内部或者环中,没有必要考虑)
对于孤立点,我们需要用至少n-1条链相连。
因此我们在其中选择 大于等于n-1条链,剩下的链自成环。
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
#define N 105
#define mod 10000007
#define ll long long
ll in[N], out[N], n;
vector<ll>E[N];
ll D[N], C[N][N];
ll dfs(ll u){
if(!E[u].size())return 1;
return 1+dfs(E[u][0]);
}
void init(){
for(ll i = 0; i <= n; i++)E[i].clear();
memset(in, 0, sizeof in);
memset(out, 0, sizeof out);
}
int main(){
ll i, j;
D[0] = 1, D[1] = 0;
for(i=2;i<N;i++)D[i] = (i-1)*(D[i-2]+D[i-1]), D[i]%=mod;
for(i = 0; i < N; i++)
{
C[0][i] = 0;
C[i][0] = 1;
}
for(i = 1; i < N; i++)
{
for(j = 1; j < N; j++)
C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
}
while(scanf("%lld",&n),n){
init();
bool yes = false;
for(i=1;i<=n;i++){
char s[N];scanf("%s",s);
for(j=1;s[j-1];j++) if(s[j-1]=='Y')
{
if(i==j)yes = true;
in[j]++, out[i]++;
E[i].push_back(j);
}
}
for(i = 1; i <= n; i++)if(in[i]>=2 || E[i].size()>=2)yes = true;
if(yes || n==1){puts("0");continue;}
ll st[N], top = 0;
for(i = 1; i <= n; i++) if(in[i]==0)st[top++] = dfs(i);
sort(st, st+top);
ll num = upper_bound(st, st+top, 1)-st;
ll left = top - num;
ll ans = 0;
for(i = num; i <= top; i++)
ans += C[left][i-num]*D[i], ans %= mod;
printf("%lld\n",ans%mod);
}
return 0;
}
/*
2
NN
NN
2
NY
YN
3
NNN
NNN
NNN
3
NYY
NNN
NNN
0
*/