1804: 有向无环图
Time Limit: 5 Sec Memory Limit: 128 Mb Submitted: 573 Solved: 245Description
Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
为了方便,点用 1,2,…,n 编号。 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0),Bobo 想知道
除以 (10
9+7) 的余数。
其中,a
i,b
j 是给定的数列。
Input
输入包含不超过 15 组数据。
每组数据的第一行包含两个整数 n,m (1≤n,m≤10
5).
接下来 n 行的第 i 行包含两个整数 a
i,b
i (0≤a
i,b
i≤10
9).
最后 m 行的第 i 行包含两个整数 u
i,v
i,代表一条从点 u
i 到 v
i 的边 (1≤u
i,v
i≤n)。
Output
对于每组数据,输出一个整数表示要求的值。
Sample Input
3 3 1 1 1 1 1 1 1 2 1 3 2 3 2 2 1 0 0 2 1 2 1 2 2 1 500000000 0 0 500000000 1 2
Sample Output
4 4 250000014
Hint
Source
湖南省第十二届大学生计算机程序设计竞赛
本来看到题,想的是邻接表深搜路径,然后看到1E5的数据,瞬间爆炸,看了题解,用的是拓扑排序,按顺序输出题中需要输出的公式
每次将入度为0的点加入队列,然后将前后a b进行计算,时间在O(n2)以内
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<math.h>
#include<queue>
#include<vector>
using namespace std;
#define mod 1000000007
#define N 100005
#define LL long long
LL dp[N];
LL a[N],b[N];
int n,m;
int in[N];
vector<int>vec[N];
queue<int>Q;
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
int i,j;
LL ask ;
while(!Q.empty())
Q.pop();
for(i = 0; i < 100005; i++)
vec[i].clear();
memset(in,0,sizeof(in));
memset(dp,0,sizeof(dp));
for(i = 1; i <= n; i++)
{
scanf("%lld %lld",&a[i],&b[i]);
}
while(m--)
{
int x,y;
scanf("%d %d",&x,&y);
in[y]++;
vec[x].push_back(y);
}
for(i = 1; i <= n; i++)
{
if(in[i] == 0)
{
Q.push(i);///加入没有入度的节点
}
}
while(!Q.empty())
{
int x = Q.front();
//cout<<x<<endl; 1-->2-->3
Q.pop();
for(i = 0; i < vec[x].size(); i++)
{
int y = vec[x][i];
//cout<<y<<endl; 2-->3-->3
in[y] --;
if(in[y] == 0)///继续加入,进行拓扑排序
Q.push(y);
dp[y] = dp[y]+a[x]*b[y]%mod;
dp[y]%=mod;
a[y] = a[y] + a[x];///对下一个节点的拉伸计算
a[y]%=mod;
//ask = dp[y];
}
}
ask = 0;
for(i = 1; i <= n; i++)
{
ask = ask + dp[i];
ask %= mod;
}
printf("%lld\n",ask);
}
return 0;
}
/*typedef long long LL;
LL mod = 1e9+7;
LL dp[100005];
int cnt[100005];
LL a[100005];
LL b[100005];
vector<int>vec[100005];
queue<int>que;
int main(void)
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
int i,j;LL ask ;
while(!que.empty())
que.pop();
for(i = 0; i < 100005; i++)
vec[i].clear();
memset(cnt,0,sizeof(cnt));
memset(dp,0,sizeof(dp));
for(i = 1; i <= n; i++)
{
scanf("%lld %lld",&a[i],&b[i]);
}
while(m--)
{
int x,y;
scanf("%d %d",&x,&y);
cnt[y]++;
vec[x].push_back(y);
}
for(i = 1; i <= n; i++)
{
if(cnt[i] == 0)
{
que.push(i);///加入没有入度的节点
}
}
while(!que.empty())
{
int x = que.front();
//cout<<x<<endl; 1-->2-->3
que.pop();
for(i = 0;i < vec[x].size();i++)
{
int y = vec[x][i];
//cout<<y<<endl; 2-->3-->3
cnt[y] --;
if(cnt[y] == 0)///继续加入,进行拓扑排序
que.push(y);
dp[y] = dp[y]+a[x]*b[y]%mod;
dp[y]%=mod;
a[y] = a[y] + a[x];///对下一个节点的拉伸计算
a[y]%=mod;
//ask = dp[y];
}
}
ask = 0;
for(i = 1;i <= n;i++)
{
ask = ask + dp[i];
ask %= mod;
}
printf("%lld\n",ask);
}
return 0;
}*/