【数据范围】
输入数据保证 1 号城市可以到达n 号城市。
对于 10%的数据,1≤n≤6。
对于 30%的数据,1≤n≤100。
对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。
对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市
水晶球价格≤100。
题解:spfa
我们从1开始跑spfa,对于每一个点求路径上的最小值min[i],然后反向建图,从n点开始跑spfa,对于每个点求路径上的最大值max[i]。
ans=max{max[i]-min[i]} 。一开始就是这么想的,但是觉得如果是到达后面的点再跑回前面的点,再到达终点这种情况处理不了。其实是可以的到
因为如果后面的点比前面的点小,那么他想要后面的点与前面的点进行贸易,那后面的点必然存在路径到达前面的点,那么跑spfa的时候就会用他的值来更新
前面点的最小值,求最大值也是同理。
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#define N 1000003using namespace std;int m,n,tot,tot1;int point[N],v[N],c[N],next[N];int head[N],nextn[N],vn[N],cn[N];int dis[N],disn[N],can[N];int a[N],fa[N];void spfa(int s){memset(can,0,sizeof(can));queue<int> p;can[s]=1; dis[s]=a[s]; p.push(s);while(!p.empty()){int now=p.front(); p.pop();for (int i=point[now];i;i=next[i]) if (dis[v[i]]>dis[now]) { dis[v[i]]=dis[now]; dis[v[i]]=min(dis[v[i]],a[v[i]]); if (!can[v[i]]) { can[v[i]]=1; p.push(v[i]); } }can[now]=0;}}void spfa1(int s){memset(can,0,sizeof(can));queue<int> p;can[s]=1; disn[s]=a[s]; p.push(s);while(!p.empty()){int now=p.front(); p.pop();for (int i=head[now];i;i=nextn[i]) if (disn[vn[i]]<disn[now]) { disn[vn[i]]=disn[now]; disn[vn[i]]=max(disn[vn[i]],a[vn[i]]); if (!can[vn[i]]) { can[vn[i]]=1; p.push(vn[i]); } }can[now]=1;}}void add(int x,int y){tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;//cout<<x<<" "<<y<<endl;}void add1(int x,int y){tot1++; nextn[tot1]=head[x]; head[x]=tot1; vn[tot1]=y;//cout<<x<<" "<<y<<endl;}int main(){freopen("a.in","r",stdin);scanf("%d%d",&n,&m);for (int i=1;i<=n;i++) { scanf("%d",&a[i]); }memset(dis,127/3,sizeof(dis));memset(disn,-1,sizeof(disn));for (int i=1;i<=m;i++){int x,y,z; scanf("%d%d%d",&x,&y,&z);if (z==1) { add(x,y); add1(y,x); }else { add(x,y); add(y,x); add1(y,x); add1(x,y); }}spfa(1); spfa1(n);//for (int i=1;i<=n;i++) //cout<<disn[i]<<" "<<dis[i]<<endl;int ans=0;for (int i=1;i<=n;i++) ans=max(ans,disn[i]-dis[i]);printf("%d\n",ans);}