题型:图论
题意:
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 0x3f3f3f3f
using 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 10
1 2 4
1 4 1
4 3 1
2 5 1
4 5 2
3 2 1
1
3
1
2 2
*/