ZOJ 3794 Greedy Driver

Greedy Driver

题意

1.有个卡车司机叫爱德华,他现在任务是从1到n。
2.图上有m条有向边。
3.有p个点是加油站,他在加油站可以免费加油,加任意多的油,但是不能超过油箱上限C。
4有Q个点可以卖油,qi点,每桶油可以卖vi元,但是最多只能卖一次。
5.他想在完成任务的情况下赚尽可能多的钱。(如果不能到达n 输出-1)
6.问他最多能赚多少钱?

1.只能在一个点卖,则枚举出售点
2.预处理 dis1[qi]:1->qi最多留下的油量
3.预处理 dis2[qi]:qi->n至少需要的油量
4.ans=max(dis1[qi]-dis2[qi],ans)
5.这题同时存在正边和负边,dj是可以被卡的(虽然我过了),所以最好用spfa

具体代码

#include<bits/stdc++.h>
using namespace std;
const int M=1005;
typedef pair<int,int>P;
int n,m,TP,q;
int asdf,head[M],rhead[M],rasdf;
bool oil[M];
struct edge {
    int to,nxt,cost;
} G[M*200],rG[M*200];
void add_edge(int a,int b,int c) {
    G[++asdf].to=b;
    G[asdf].nxt=head[a];
    G[asdf].cost=c;
    head[a]=asdf;
}
void radd_edge(int a,int b,int c) {
    rG[++rasdf].to=b;
    rG[rasdf].nxt=rhead[a];
    rG[rasdf].cost=c;
    rhead[a]=rasdf;
}
//只能在一个点卖油
//枚举在哪里卖油 用1->qi最多留下的油量 - qi->n至少需要的油量
int dis1[M],dis2[M];
bool vis[M];
void spfa(int S,int D) {
    queue<int>Q;
    for(int i=1; i<=n; i++) {
        dis1[i]=-1;
        vis[i]=0;
    }
    dis1[S]=D;
    vis[S]=1;
    Q.push(S);
    while(!Q.empty()) {
        int x=Q.front();
        Q.pop();
        vis[x]=0;
        for(int i=head[x]; i; i=G[i].nxt) {
            if(dis1[x]-G[i].cost<0)continue;
            int y=G[i].to;
            int cost=dis1[x]-G[i].cost;
            if(oil[y])cost=TP;
            if(dis1[y]<cost) {
                dis1[y]=cost;
                if(!vis[y]) {
                    Q.push(y);
                }
            }
        }
    }
}
void rspfa(int S,int D) {
    queue<int>Q;
    for(int i=1; i<=n; i++) {
        dis2[i]=1e9;
        vis[i]=0;
    }
    dis2[S]=D;
    vis[S]=1;
    Q.push(S);
    while(!Q.empty()) {
        int x=Q.front();
        Q.pop();
        for(int i=rhead[x]; i; i=rG[i].nxt) {
            int y=rG[i].to;
            if(rG[i].cost+dis2[x]>TP)continue;
            int cost=dis2[x]+rG[i].cost;
            if(oil[y])cost=0;
            if(dis2[y]>cost) {
                dis2[y]=cost;
                if(!vis[y])Q.push(y);
            }
        }
    }
}
int main() {
    int a,b,c;
    while(scanf("%d %d %d",&n,&m,&TP)==3) {
        asdf=rasdf=0;
        for(int i=1; i<=n; i++)head[i]=rhead[i]=oil[i]=0;
        for(int i=1; i<=m; i++) {
            scanf("%d %d %d",&a,&b,&c);
            add_edge(a,b,c);
            radd_edge(b,a,c);
        }
        scanf("%d",&q);
        for(int i=1; i<=q; i++) {
            scanf("%d",&a);
            oil[a]=1;
        }
        spfa(1,TP);
        rspfa(n,0);
        scanf("%d",&q);
        int ans=-1;
        if(dis1[n]>=0)ans=0;
        for(int i=1; i<=q; i++) {
            scanf("%d %d",&a,&b);
            if(dis1[a]==-1||dis2[a]==1e9)continue;
            if(dis1[a]>=dis2[a]) {
                ans=max(ans,(dis1[a]-dis2[a])*b);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值