ZOJ_3794_Greedy Driver(单源最短路)

来源:互联网 发布:中国东盟贸易数据 编辑:程序博客网 时间:2024/05/16 02:16

题型:图论


题意:

      n个city,m条边。一个司机从1点开车到n点,每条边都有耗油量w,有一些点是加油站,有一些点是可以卖油点且每个卖油点都有各自的卖油单价val。司机遇到加油站是就可以把油加满,中途只能卖一次油。问司机从1点出发至n点后最多可以赚多少油钱。


分析:

      直观上,每条路径上安排几个卖油点或者是几个加油站是做不到的。转而想,既然中途只能买一次油,那么只需枚举卖油点即可。

      当到达卖油点 i 时,设从起点到该卖油点所剩的最大油量为Left,从该卖油点抵达终点所需的最少耗油量为Cost,则有

                                              Sell = Left - Cost

      要追求的是最大的Sell量,所以需要Left尽量大而cost尽量小。

      对于Left的求解,可以想象成为从起点到各个点的最短路径的变形,求到每个点的油最大剩余量,起点油量为c,遇到加油站时,剩余油量变为c。

      对于Cost的求解,可以想象成为从终点到各个点的最短路径的变形,求终点到各个点的最少耗油量,终点耗油量为0,遇到加油站耗油量为0。 


代码:

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<queue>#define mt(a,b) sizeof(a,b,sizeof(a));#define M 1234#define INF 0x3f3f3f3fusing namespace std;int n,m,c;struct G {    struct E {        int u;        int v;        int w;        int next;    } e[M*M];    int le,head[M];    void init() {        le = 0;        memset(head,-1,sizeof(head));    }    void add(int u,int v,int w) {        e[le].u = u;        e[le].v = v;        e[le].w = w;        e[le].next = head[u];        head[u] = le++;    }} g1,g2; //原图和反图int dis1[M],dis2[M];bool used[M];bool station[M],sell[M];void SPFA_from_start() {    queue<int> q;    q.push(1);    used[1] = true;    dis1[1] = c;    while(!q.empty()) {        int u = q.front();        q.pop();        used[u] = false;        for(int i=g1.head[u]; i!=-1; i=g1.e[i].next) {            int v = g1.e[i].v;            int w = g1.e[i].w;            if(dis1[u] < w) continue;            if(station[v]) {                if(dis1[v]<c)                {                    dis1[v] = c;                    if(!used[v]) {                        used[v] = true;                        q.push(v);                    }                }            } else {                if(dis1[v] < dis1[u] - w) {                    dis1[v] = dis1[u] - w;                    if(!used[v]) {                        used[v] = true;                        q.push(v);                    }                }            }        }    }}void SPFA_from_end() {    queue<int> q;    q.push(n);    used[n] = true;    dis2[n] = 0;    while(!q.empty()) {        int u = q.front();        q.pop();        used[u] = false;        for(int i=g2.head[u]; i!=-1; i=g2.e[i].next) {            int v = g2.e[i].v;            int w = g2.e[i].w;            if(dis2[u]+w>c)continue;            if(station[v]) {                if(dis2[v]>0) {                    dis2[v]=0;                    if(!used[v]) {                        used[v]=true;                        q.push(v);                    }                }            } else {                if(dis2[v]>dis2[u]+w) {                    dis2[v]=dis2[u]+w;                    if(!used[v]) {                        used[v]=true;                        q.push(v);                    }                }            }        }    }}int main() {    int P,Q;    while(~scanf("%d%d%d",&n,&m,&c)) {        g1.init();        g2.init();        int u,v,w;        for(int i=0; i<m; i++) {            scanf("%d%d%d",&u,&v,&w);            g1.add(u,v,w);            g2.add(v,u,w);        }        memset(station,false,sizeof(station));        memset(sell,false,sizeof(sell));        scanf("%d",&P);        int tmp;        for(int i=0; i<P; i++) {            scanf("%d",&tmp);            station[tmp] = true;        }        memset(dis1,-1,sizeof(dis1));        for(int i=0; i<=M; i++) {            dis2[i] = INF;        }        memset(used,false,sizeof(used));        SPFA_from_start();        memset(used,false,sizeof(used));        SPFA_from_end();        scanf("%d",&Q);        int id,value;        int ans = 0;        while(Q--){            scanf("%d%d",&id,&value);            if(dis1[id]>=0&&dis2[id]<=c) {                ans=max(ans,(dis1[id]-dis2[id])*value);            }        }        if(dis1[n]<0)ans=-1;        printf("%d\n",ans);    }    return 0;}/*5 6 101 2 41 4 14 3 12 5 14 5 23 2 11312 2*/


0 0
原创粉丝点击