题目:In Chinese Restaurant:URAL - 1962
题意:
有N个人要坐在一张圆桌上,给出M对关系K[1..M],表示第i个人想坐在k[i]边上。问存在多少种不同的分配方案,结果模1e9+7。1号玩家位置固定.
思路:
统计每个人的入度,如果有人入度大于2则无解。利用并查集将想坐在一起的人合并起来,个数记为sn,以及集合人数大于1的个数c,同时要小心可能存在环。如果sn>1并且存在环的话无解。如果N=2则解为1。其他情况下,答案为 (sn−1)!∗2c
代码:
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int INF=1e9+7;
int d[300],f[300],sz[300],b[300][300];
int sf(int d){return f[d]==d? d:f[d]=sf(f[d]);}
main(){
bool flag=0,ok=0;
int n,m,num,ans=1,x;cin >>n>>m;num=n;
if (n==2) return puts("1");
for (int i=1;i<=n;++i) f[i]=i;
for (int i=1;i<=n;++i) sz[i]=1;
for (int i=1;i<=m;++i){
cin >>x;int fx=sf(i),fy=sf(x);
if (b[x][i]||b[i][x]) continue;
++d[x];++d[i];b[i][x]=b[x][i]=1;
if (fx!=fy){
num--;
f[fx]=fy;sz[fy]++;sz[fx]=0;
}else ok=1;
}
for (int i=1;i<=n;++i) if (d[i]>2) flag=1;
if (flag||ok&&num>1) return puts("0");
for (int i=1;i<num;++i) ans=(ans*i)%INF;
for (int i=1;i<=n;++i) if (sz[i]>1) ans=(ans*2)%INF;
cout <<ans<<endl;return 0;
}