拓扑图DP
对于拓扑图,deg[i]表示i的入度,根为1,答案就是 ∏ni=2deg[i]
即除根节点外,每个点都选择一条入边,由于图是DAG,因此一定会形成一个树形图(听说这是朱刘算法的推论?)
考虑加完边之后有环怎么办?只要在答案里减去环的贡献即可。如何求环的贡献?当环的边全部被选时,方案数肯定是所有非环上点(除了根1)的入度之积。脑补即可证明。因此需要特判y=1。
附大爷题解:http://blog.youkuaiyun.com/popoqqq/article/details/45194103
#include<cstdio>
#include<queue>
#define ll long long
#define N 100005
#define MOD 1000000007
#define M 200005
using namespace std;
struct edge{int next,to;}e[M];
ll f[N];
int last[N], ecnt=1, deg[N], in[N], inv[M], n, m, x, y; ;
void add(int a, int b)
{
e[++ecnt]=(edge){last[a],b};
last[a]=ecnt;
}
void init()
{
inv[1]=1;
for(int i = 2, ii = m+1; i <= ii; i++)
inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
}
void DP()
{
init();
queue<int> q;
q.push(1);
f[y]=1;
while(!q.empty())
{
int u = q.front();
if(x==u)break;
q.pop();
f[u]=f[u]*inv[deg[u]]%MOD;
for(int i = last[u]; i; i=e[i].next)
{
int v=e[i].to;
f[v]=(f[v]+f[u])%MOD;
in[v]--;
if(!in[v])
q.push(v);
}
}
f[x]=f[x]*inv[deg[x]]%MOD;
}
int main()
{
ll ans=1;
scanf("%d%d%d%d",&n,&m,&x,&y);
deg[y]++;
for(int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d",&a,&b);
add(a,b);
deg[b]++;
in[b]++;
}
for(int i = 2; i <= n; i++)
ans=ans*deg[i]%MOD;
if(y==1)
{
printf("%lld\n",ans);
return 0;
}
DP();
printf("%lld\n",(ans-ans*f[x]%MOD+MOD)%MOD);
}