题意:一个人要从1走到n,他有一个加油卡,可以再任意一个有加油站的地方免费加油,走每条道路要花费一定的汽油,有一些城市可以卖汽油赚钱,他想要在能到达n的前提下,尽量赚更多的钱,但是他只能卖一次汽油,问这个人能获得的最大收益是多少。
思路:求两次最短路,第一次从起点开始,求从起点到达这个位置时能保留的最多的汽油的量,另一次从终点开始,计算从某一点到达终点至少需要多少汽油。然后就可以枚举一下可以卖汽油的位置,将第一次得到的值减去第二次得到的值就是能卖掉的最多的汽油了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-6
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1000+10;
const int maxm=100000+10;
struct Edge
{
int v,w,next;
Edge(){}
Edge(int v,int w,int next):v(v),w(w),next(next){}
}edges[maxm<<1];
int head[maxn],dmax[maxn],dmin[maxn],nEdge;
int fuel[maxn],sell[maxn],n,m,C;
bool inq[maxn];
void AddEdges(int u,int v,int w)
{
edges[++nEdge]=Edge(v,w,head[u]);
head[u]=nEdge;
edges[++nEdge]=Edge(u,w,head[v]);
head[v]=nEdge;
}
void fmax(int s)
{
memset(dmax,0xff,sizeof(dmax));
memset(inq,0,sizeof(inq));
queue<int>q;
q.push(s);
dmax[s]=C;
while(!q.empty())
{
int u=q.front();q.pop();
inq[u]=false;
for(int k=head[u];k!=-1;k=edges[k].next)
{
if(dmax[u]<edges[k].w||(k&1)) continue;
int v=edges[k].v;
if(dmax[v]<dmax[u]-edges[k].w)
{
if(fuel[v]) dmax[v]=C;
else dmax[v]=dmax[u]-edges[k].w;
if(!inq[v]) {inq[v]=true;q.push(v);}
}
}
}
}
void fmin(int s)
{
memset(dmin,0x3f,sizeof(dmin));
memset(inq,0,sizeof(inq));
queue<int>q;
q.push(s);
dmin[s]=0;
while(!q.empty())
{
int u=q.front();q.pop();
inq[u]=false;
for(int k=head[u];k!=-1;k=edges[k].next)
{
if(dmin[u]+edges[k].w>C||(k%2==0)) continue;
int v=edges[k].v;
if(dmin[v]>dmin[u]+edges[k].w)
{
if(fuel[v]) dmin[v]=0;
else dmin[v]=dmin[u]+edges[k].w;
if(!inq[v]) {inq[v]=true;q.push(v);}
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d%d",&n,&m,&C))
{
memset(head,0xff,sizeof(head));
memset(fuel,0,sizeof(fuel));
memset(sell,0,sizeof(sell));
nEdge=-1;
int u,v,w;
for(int i=0;i<m;++i)
{
scanf("%d%d%d",&u,&v,&w);
AddEdges(u,v,w);
}
int P,Q;
scanf("%d",&P);
while(P--)
{
scanf("%d",&u);
fuel[u]=1;
}
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d",&u,&w);
sell[u]=w;
}
fmax(1);
fmin(n);
int ans=0,tmp;
for(int i=1;i<=n;++i)
if(sell[i]&&dmax[i]!=-1&&dmin[i]!=inf)
{
tmp=(dmax[i]-dmin[i])*sell[i];
ans=max(ans,tmp);
}
if(dmax[n]==-1) ans=-1;
printf("%d\n",ans);
}
return 0;
}