2018牛客网多校

本文介绍了解决网格图中不相交路径计数问题的Lindström–Gessel–Viennot引理,并给出了一种计算方法。此外,还探讨了通过暴力匹配解决图同构问题的方法,利用哈希去重或考虑自同构方案数来提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A – (Lindström–Gessel–Viennot lemma)

这个定理是解决网格图不相交路径计数的
这里写图片描述
本题就相当于在一个n*m的网格中求两条不相交的线。这里写图片描述
题解:01 和 12 的分界线 是 (n, 0) 到 (0, m) 的两条不相交(可重合)路径 平移其中一条变成 (n-1, -1) 到 (-1, m-1) 变成起点 (n, 0) 和 (n-1, -1),终点 (0, m) 和 (-1, m-1) 的严格不相交路径
套 Lindström–Gessel–Viennot lemma
答案是 C(n+m, n )*C (n+m,n) - C(n+m, m - 1)*C(n+m, n-1)

#include<bits/stdc++.h>
using namespace std;
#define maxn 2005
#define mod 1000000007
#define ll long long
ll a[maxn][maxn];
int main()
{
     a[0][0]=a[1][0]=a[1][1]=1;
    for(int i=2;i<=2000;i++){
        a[i][0]=1;
        for(int j=1;j<=i;j++)
            a[i][j]=(a[i-1][j]+a[i-1][j-1])%mod;
    }
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF){
        ll s1=a[n+m][n]*a[n+m][m]%mod;
        ll s2=a[n+m][m-1]*a[n+m][n-1]%mod;
        ll ans=(s1-s2+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

D – (暴力匹配)

直接n ! 枚举可能的同构方案
Hash 去重即可 ,也可除以自同构的方案数

#include<bits/stdc++.h>
using namespace std;
const int maxn=10;
struct node{
    int t,next;
}chu[100];
int head[maxn];
int sz;
void add(int f,int t)
{
   chu[sz].t=t;
   chu[sz].next=head[f];
   head[f]=sz++;
}
int mp2[10][10],mp1[10][10];
int qu[100],biao[100],ans,ans2,n;
void init()
{
    memset(mp2,0,sizeof(mp2));
    memset(mp1,0,sizeof(mp1));
    memset(biao,0,sizeof(biao));
    ans=0,ans2=0;
    memset(head,-1,sizeof(head));
    sz=0;
}
bool suan1()
{
    bool fa=true;
    for(int i=1;i<=n&&fa;i++){
        for(int j=head[i];~j;j=chu[j].next)
        {
            int to=chu[j].t;
        //  cout<<i<<" "<<to<<endl;
            if(mp2[qu[i]][qu[to]]==0) {fa=false;break;}
        }
    }
    //cout<<endl;
    if(fa) return true;
    else return false;
}
bool suan2()
{
    bool fa=true;
    for(int i=1;i<=n&&fa;i++){
        for(int j=head[i];~j;j=chu[j].next)
        {
            int to=chu[j].t;
            if(mp1[qu[i]][qu[to]]==0) {fa=false;break;}
        }
    }
    if(fa) return true;
    else return false;
}
void dfs(int cn)
{
    if(cn>n){
        if(suan1()) ans++;
        if(suan2()) ans2++;
        return;
    }
    for(int i=1;i<=n;i++){
        if(biao[i]==0){
            biao[i]=1;
            qu[cn]=i;
            dfs(cn+1);
            biao[i]=0;
        }
    }
    return;
}
int main()
{
    int num1,num2;
    while(scanf("%d %d %d",&n,&num1,&num2)!=EOF)
    {
       init();
       for(int i=0;i<num1;i++) {
        int u,v;
        scanf("%d %d",&u,&v);
        add(u,v);add(v,u);
        mp1[u][v]=mp1[v][u]=1;
       }
       for(int i=0;i<num2;i++) {
        int u,v;
        scanf("%d %d",&u,&v);
        mp2[u][v]=mp2[v][u]=1;
       }
       dfs(1);
      // cout<<ans<<" "<<ans2<<endl;
       printf("%d\n",ans/ans2);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值