 /**//*
題意:給出一個有向圖,現可以加邊,問有多少種方案使得圖上的每個點在且僅在一個環中
而且除了環邊外沒有多余的邊(不用加邊也算一種方案)

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
搜索
最新評論

|
|