csu1804: 有向无环图(拓扑排序+dp)

1804: 有向无环图

Submit Page      Summary      Time Limit: 5 Sec       Memory Limit: 128 Mb       Submitted: 573       Solved: 245    

Description

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
#include
#include
#include
#include
#include
#include
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];
vectorvec[N];
queueQ;

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<2-->3
            Q.pop();
            for(i = 0; i < vec[x].size(); i++)
            {
                int y = vec[x][i];
                //cout<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];
vectorvec[100005];
queueque;
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<2-->3
                    que.pop();
                    for(i = 0;i < vec[x].size();i++)
                    {
                        int y = vec[x][i];
                        //cout<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;
}*/




你可能感兴趣的:(排序,ACM_DP_动态规划)