2骑士 题解(拓扑排序+动态规划+容斥原理)

Posted invictus-ocean

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2骑士 题解(拓扑排序+动态规划+容斥原理)相关的知识,希望对你有一定的参考价值。

题目描述

上周的题目中我们知道,骑士之间彼此存在爱慕。其实作为一名有情有义的骑士,往往都有真爱的异性。现在有两个骑士,他们不幸爱上了同一个异性,爱之深,恨之切,他们因此非常厌恶自己的情敌。他们不共戴天,不愿意和对方有所瓜葛。

现在他们各自被要求执行一个任务,分别是从城a1到a2,从城b1b2,他们不愿意和对方经过相同的地点,骑士团长很困扰,想知道有多少种方案。注意这个王国地形特殊,所有道路都是单向的,且从任何一个城出发如果不一直逆向行驶是回不到起点的。

输入格式

第一行 n,m

2-m+1行 建图

m+2行 a1,a2,b1,b2

1<=n<=200,1<=m<=5000

---------------------------------------------------------------------------------------------------------------------------------

经过了深刻地思考,你会发现,由于这是一个DAG图,我们可以将其转化为动态规划来做,同时我们先要将图建立成一个拓扑图。

然后你又经过了深刻地思考,你会发现这道题还需要容斥原理。

假设g[i]是从a1和b1到共同点i的路径总方案数,则可以得

g[i]=f[a1][i]*f[b1][i]-sigma(g[k]*f[k][i]^2)(1<=k<i)  原谅博主不会用数学工具

则可以得

ans=f[a1][b1]*f[a2][b2]-sigma(g[k]*f[k][a2]*f[k][b2])(1<=k<=n)

由于数据范围较小,知道了思路是个OIer都有方法将其实现,不存在卡时间的问题。

#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int maxn=205;
struct node
{
    int next,to;
}edge[200005];
int head[200005];
int g[maxn],f[maxn][maxn],in[maxn],pos[maxn];
int n,m,u,v,a,b,c,d,cnt,tot,ans;
queue<int> q;
void add(int from,int to)
{
    edge[++tot].next=head[from];
    edge[tot].to=to;
    head[from]=tot;
    in[to]++;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch==-) f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
signed main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++)
    {
        u=read(),v=read();
        add(u,v);
    }
    a=read(),b=read(),c=read(),d=read();
    for (int i=1;i<=n;i++) if (!in[i]) q.push(i);
    while(!q.empty())
    {
        int now=q.front();q.pop();
        pos[++cnt]=now;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            in[to]--;
            if (!in[to]) q.push(to);
        }
    }
    for (int i=1;i<=n;i++)
    {
        u=pos[i];f[u][u]=1;
        for (int j=i;j<=n;j++)
        {
            v=pos[j];
            for (int k=head[v];k;k=edge[k].next){
                int to=edge[k].to;
                f[u][to]+=f[u][v];
            }
        }
    }
    for (int i=1;i<=n;i++)
    {
        u=pos[i];
        g[u]=f[a][u]*f[c][u];
        for (int j=1;j<i;j++)
        {
            v=pos[j];
            g[u]-=g[v]*f[v][u]*f[v][u];
        }
    }
    ans=f[a][b]*f[c][d];
    for (int i=1;i<=n;i++) u=pos[i],ans-=g[u]*f[u][b]*f[u][d];
    printf("%lld",ans);
    return 0;
}

后注:因为作者“深刻地思考”的时间太长,导致现在通宵了。你看到的发布时间实际上是我熬了一晚上的结果(话说人生第一次通宵还有点激动

 

以上是关于2骑士 题解(拓扑排序+动态规划+容斥原理)的主要内容,如果未能解决你的问题,请参考以下文章

51Nod1518 稳定多米诺覆盖 动态规划 插头dp 容斥原理

状态压缩动态规划:骑士题解

[bzoj3622]已经没有什么好害怕的了_动态规划_容斥原理

洛谷P1450 [HAOI2008]硬币购物 动态规划 + 容斥原理

51Nod1317 相似字符串对 容斥原理 动态规划

bzoj 4767 两双手 - 动态规划 - 容斥原理