【拓扑排序+dp】Hzy's Rabbit Candy

Hzy's Rabbit Candy

 

题目描述

Hzy和她的m只兔兔在一个n个点m条边的有向无环图上玩。

为了让兔兔们开心,Hzy带了一些糖。Hzy可以从任何一个点开始,走到任何一个点结束。在这途中,每当Hzy经过一个点i,她会捡到ai块糖;每当Hzy经过一条边j,这条边上的兔兔会吃掉她的bj块糖。

Hzy希望能在结束时保留尽量少的糖,请求出Hzy在结束时的糖的数量相对于开始时的糖的数量最多减少多少(请注意,Hzy的糖可能无论如何都无法减少,此时答案是一个非正整数)。

 

输入

第一行两个正整数n、m(1≤n≤100000,1≤m≤500000),表示点数和边数。
之后的一行n个正整数以空格隔开,第i个正整数ai表示经过第i个点Hzy会捡到的糖的数量。
之后的m行,每行三个正整数uj,vj,bj,表示一条从uj到vj的边,Hzy经过这条边时,兔兔会吃掉bj块糖。

 

输出

一行一个正整数,表示Hzy在结束时的糖的数量相对于开始时的糖的数量最多减少多少。

 

样例输入

复制样例数据

3 5
1 2 3
1 2 10
1 2 11
2 3 10
2 3 11
1 3 15

样例输出

16

【题意】:

可以  以任何点为起点,和终点。然后到达该点会获得a[i],然后经过这条边就会减少相应的边的权值。

然后问,请问怎样才能减少的最多。

【题解】:

首先我们应该反着想,你不说减少最多吗?而且求最大的减少量,那么这个其实可以反着题目。

题目说到达某点时会增加,你看作减少,经过某边减少权值,你可以看作增加。

然后进行拓扑排序,然后在过程中更新dp[ ] 来实现。

具体可以看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10;
typedef struct Edge{
    int to,next,w;
    Edge(int to=0,int next=0,int w=0):to(to),next(next),w(w){}
}Edge;
Edge e[N];
int head[N],cnt=0;
void add_edge(int u,int v,int w){
    e[cnt]=Edge(v,head[u],w);
    head[u]=cnt++;
}
ll dp[N];
int a[N];
int du[N];
int main()
{
    memset(head,-1,sizeof(head));
    int n,m;
    ll ans=-N;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i]=-a[i];
        dp[i]=a[i];
        ans=max(ans,dp[i]);
    }
    for(int i=0;i<m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
        du[v]++;
    }
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(!du[i]){
            q.push(i);
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=e[i].next){
            int to=e[i].to;
            ll tmp=dp[u]+e[i].w+a[to];
            dp[to]=max(dp[to],tmp);
            ans=max(ans,dp[to]);
            du[to]--;
            if(du[to]==0){
                q.push(to);
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值