洛谷 P1073 最优贸易 & [NOIP2009提高组](反向最短路)
传送门
解题思路
很长的题,实际上在一个有向图(点有点权)中求一个从起点1到终点n的路径,使得这条路径上点权最大的点与点权最小的点的差值最大(要求必须从点权较小的点能够走到点权较大的点)。
——最短路??
——不像呀。
(可是洛谷标签上写着呀)
就是一个写起来像最短路的一个图中的dp。
我们用dis1[i]表示从1号点到第i号点的路径上的最小值,用dis2[i]表示从i号点到第n号点的最大值,最后只需要找出最大的(dis2[i]-dis1[i])即可。
怎么求dis2呢?这里有一种方法——建反图。
建反图就是把每一条有向边反过来,例如原来是u-->v,现在变成了v-->u。
然后从n开始,跑一遍n到各个点的最短路,求出dis2数组。
对于dis数组,dis[i的儿子k]=dis[i],v[k](k号点本身的数值),dis[k]中的最小值/最大值。
用dijkstra或者spfa跑一遍图就可以了。
当年,spfa还没有死去。
AC代码
1 #include<iostream> 2 #include<queue> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 const int maxn=100005; 7 const int maxm=1000005;//注意有可能是双向边,所以要开两倍的数组。 8 int n,m,p1[maxn],p2[maxn],cnt1,cnt2,vis[maxn],dis1[maxn],dis2[maxn],ans,v[maxn]; 9 struct edge{ 10 int v,next; 11 }e1[maxm],e2[maxm]; //两个图 12 void insert1(int u,int v){ //两个insert 13 cnt1++; 14 e1[cnt1].v=v; 15 e1[cnt1].next=p1[u]; 16 p1[u]=cnt1; 17 } 18 void insert2(int u,int v){ 19 cnt2++; 20 e2[cnt2].v=v; 21 e2[cnt2].next=p2[u]; 22 p2[u]=cnt2; 23 } 24 struct node{ 25 int num,len; 26 }; 27 bool operator < (node a,node b){ 28 return a.len>b.len; 29 } 30 priority_queue<node> q1,q2; 31 void dijkstra1(){ //两个dijkstra 32 memset(vis,0,sizeof(vis)); 33 memset(dis1,0x3f,sizeof(dis1)); 34 dis1[1]=v[1]; 35 node nd; 36 nd.len=v[1]; 37 nd.num=1; 38 q1.push(nd); 39 while(!q1.empty()){ 40 node u=q1.top(); 41 q1.pop(); 42 if(vis[u.num]) continue; 43 vis[u.num]=1; 44 for(int i=p1[u.num];i!=-1;i=e1[i].next){ 45 dis1[e1[i].v]=min(min(dis1[e1[i].v],u.len),v[e1[i].v]);//算是个小的dp吧 46 node xin; 47 xin.num=e1[i].v; 48 xin.len=dis1[e1[i].v]; 49 q1.push(xin); 50 } 51 } 52 } 53 void dijkstra2(){ 54 memset(vis,0,sizeof(vis)); 55 memset(dis2,-0x3f,sizeof(dis2)); 56 dis2[n]=v[n]; 57 node nd; 58 nd.len=v[n]; 59 nd.num=n; 60 q2.push(nd); 61 while(!q2.empty()){ 62 node u=q2.top(); 63 q2.pop(); 64 if(vis[u.num]) continue; 65 vis[u.num]=1; 66 for(int i=p2[u.num];i!=-1;i=e2[i].next){ 67 dis2[e2[i].v]=max(max(dis2[e2[i].v],u.len),v[e2[i].v]); 68 node xin; 69 xin.num=e2[i].v; 70 xin.len=dis2[e2[i].v]; 71 q2.push(xin); 72 } 73 } 74 } 75 int main(){ 76 cin>>n>>m; 77 memset(p1,-1,sizeof(p1)); 78 memset(p2,-1,sizeof(p2)); 79 for(int i=1;i<=n;i++) cin>>v[i]; 80 for(int i=1;i<=m;i++){ 81 int x,y,z; 82 scanf("%d%d%d",&x,&y,&z); 83 if(z==1){ 84 insert1(x,y); 85 insert2(y,x); 86 }else{ 87 insert1(x,y); 88 insert1(y,x); 89 insert2(x,y); 90 insert2(y,x); 91 } 92 } 93 dijkstra1(); 94 dijkstra2(); 95 for(int i=1;i<=n;i++) ans=max(ans,dis2[i]-dis1[i]);//求出答案 96 cout<<ans; 97 return 0; 98 }
//NOIP2009提高组t3
//好困啊,zzz