拓扑排序 有向图无环

在这里插入图片描述
输入

3 3
1 1
1 1
1 1
1 2
1 3
2 3

输出
4

并不是直接计算x~y有几条路径
而是通过叠加的方式,x~ k ~ y的值 y等于x+ k1 +k2 +k3 +y
代码

#include <stdio.h>
#include <string.h>
#define ll long long
#include <queue>
#define maxn 100010
using namespace std;
ll p=1e9+7;
int head[maxn],nex[maxn],ver[maxn],tot,d[maxn],n,m;
ll a[maxn],b[maxn],s[maxn];
void init()
{
    tot=0;
    memset(d,0,sizeof(d));
    memset(head,0,sizeof(head));
}
void add(int u,int v)
{
    tot++;
    ver[tot]=v;
    nex[tot]=head[u];
    head[u]=tot;
}
int topsort()
{
    ll res=0;
    queue<int>q;
    for(int i=1;i<=n;i++)
        if(!d[i])q.push(i);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];i;i=nex[i])
        {
            int v=ver[i];
            a[v]=(a[v]+a[u])%p;              //这个点的值等于他之前的值叠加上来,即计算时把i到j所有都算了
            if(--d[v]==0)q.push(v);         //每次都将入度为0的点添加进去,
        }
    }
    for(int i=1;i<=n;i++)res=(res+(a[i]-s[i]+p)*b[i]%p)%p;      //减去s[i]是因为不能包括自己这个点的值
    return res;
}
int main()
{
    while(~scanf("%d %d",&n,&m))
    {

	    init();
    	for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]),s[i]=a[i];
    	for(int i=1;i<=m;i++)
    	{
    	    int u,v;
    	    scanf("%d %d",&u,&v);
    	    add(u,v);
    	    d[v]++;
    	}
    	printf("%lld",topsort());
	}
}	
#include <stdio.h>
#include <string.h>
#define ll long long 
#define maxn 100010
ll p=1e9+7;
int head[maxn],next[maxn],ver[maxn],tot,d[maxn];
bool vis[maxn];
ll sum[maxn],a[maxn],b[maxn],ans;
void init()
{
    tot=0;
    ans=0;
    memset(d,0,sizeof(d));
    memset(head,0,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void add(int u,int v)
{
    tot++;
    ver[tot]=v;
    next[tot]=head[u];
    head[u]=tot;
}
int dfs(int u,int fa)
{
    if(vis[u])return sum[u];
    vis[u]=1;
    ll res=0;
    for(int i=head[u];i;i=next[i])
    {
        int v=ver[i];
        if(v==fa)continue;            //不能回头 
        res=(res+dfs(v,u))%p;         //res是这条路径之后的叠加值 
    }                                 //要求i到j的值,则b[i]的值不包括在内,因为还未出现到i的父亲 
    ans=(ans+res*a[u])%p;             //res*a[u]表示这条路径的值 
    sum[u]=(res+b[u])%p;              //res+b[u]为之后的b[v]值和当前b[u]叠加,添加到它的父亲上 
    return sum[u];
}
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        init();
        for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            add(u,v);
            d[v]++;
        }
        for(int i=1;i<=n;i++)
        {
            if(!d[i])dfs(i,0);
        }
        printf("%lld\n",ans);
    }
}
发布了88 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44879687/article/details/102879712