并查集 排列组合 In Chinese Restaurant:URAL - 1962

题目: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。其他情况下,答案为 (sn1)!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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值