题目大意
有一些城市,每个城市的水晶球的售价不同。在一条从1到n的路径中,我们可以在其中一个城市买入,另一个城市卖出。
求最大收获。
算法
SPFA
先构造一个分层图,层内的边权值为0,表示随便走不需要钱。
然后第一层往第二层可以到达的点连边,权值为售价的相反数,表示买入需要花钱。
第二层往第三层可以到达的点连边,权值为售价,表示卖出可以赚钱。
然后将第一层的N和第二层的N向汇点连边,分别表示不买和买了。
然后从1开始SPFA最长路即可。
代码
#include <cstdio>
#include <queue>
#include <memory.h>
#define d1(x) (x)
#define d2(x) (x+n)
#define d3(x) (x+n+n)
struct edge{
int from,to,w,nxt;
}e[5000000];
int head[500000],cnt=0;
void add(int u,int v,int w){
e[++cnt]=(edge){u,v,w,head[u]};
head[u]=cnt;
}
int S,T;
int dis[500000]={0};
bool vis[500000]={false};
int spfa(){
std::queue<int> q;
memset(dis,-128,sizeof(dis));
q.push(S);
vis[S]=true;
dis[S]=0;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=false;
for(int i=head[x];i;i=e[i].nxt){
if(dis[e[i].to]<dis[x]+e[i].w){
dis[e[i].to]=dis[x]+e[i].w;
if(!vis[e[i].to]){
vis[e[i].to]=true;
q.push(e[i].to);
}
}
}
}
return dis[T];
}
int w[500000];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=m;i++){
int u,v,z;
scanf("%d%d%d",&u,&v,&z);
add(d1(u),d1(v),0);
add(d2(u),d2(v),0);
add(d3(u),d3(v),0);
add(d1(u),d2(v),-w[u]);
add(d2(u),d3(v),w[u]);
if(z==2){
add(d1(v),d1(u),0);
add(d2(v),d2(u),0);
add(d3(v),d3(u),0);
add(d1(v),d2(u),-w[v]);
add(d2(v),d3(u),w[v]);
}
}
S=d1(1);
T=d3(n)+1;
add(d1(n),T,0);
add(d3(n),T,0);
printf("%d\n",spfa());
return 0;
} 
京公网安备 11010502036488号