.

题意: 有n个人在圆桌上吃饭,主人位置固定,给m个关系ki表示第i个人的旁边是第ki个人,问有多少种方式可以排列…
注:这是一个圆桌,所以要分左右两边的…
给你n个人和m个关系
并查集处理下每个联通块,对(全部联通块-1)(因为1号位固定)进行全排列
再对每个元素大于1的联通块进行ans*=2,因为他们可以调转顺序
最后还有个最蛋疼的就是
n==2输出1

//URAL 1962
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
#define MM(a,x)  memset(a,x,sizeof(a));
//#define mp make_pair
#define pb push_back
#define x first
#define y second
int mod=1e9+7;
int f[200],w[200],sum[200],n,m;
void init()
{
    for(int i=1;i<=n;i++)
        w[i]=1,f[i]=i;
}
int findf(int x)
{
    if(x==f[x])
        return x;
    else return findf(f[x]);
}
void mix(int a,int b)
{
    a=findf(a);
    b=findf(b);
    w[a]=w[b]=w[a]+w[b];
    f[a]=b;
}
bool mp[200][200];
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
    //debug=1;
#endif // LOCAL
    cin>>n>>m;
    init();
    bool flag=0;
    for(int i=1;i<=m;i++)
    {
        int v;
        scanf("%d",&v);
        if(mp[v][i]||mp[i][v]) continue;
        sum[v]++;
        sum[i]++;
        if(sum[v]>2||sum[i]>2) flag=1;
        mp[i][v]=mp[v][i]=1;
        if(findf(i)!=findf(v))
            mix(i,v);
        else
        {
            if(w[findf(i)]!=n) flag=1;
        }
    }
    if(n==2) cout<<1<<endl;

   else  if(!n) cout<<0<<endl;
    else {
    if(!flag)
    {
        int cnt=0,ct=0;
        for(int i=1;i<=n;i++)
        {
            if(f[i]==i)
            {
                if(w[i]>1) cnt++;
                else ct++;
            }
        }
        LL ans=1;
        for(int i=1;i<=cnt+ct-1;i++)
            ans=(ans*i)%mod;
        if(w[findf(1)]==1)
        {
            ;
        }
        else
        {
            ans=(ans*2)%mod;
            cnt--;
        }
        for(int i=1;i<=cnt;i++)
        {
            ans=(ans*2)%mod;
        }
        cout<<ans<<endl;
    }
    else cout<<0<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值