题目大意
有一些城市,每个城市的水晶球的售价不同。在一条从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; }