Luogu P1073 最优贸易【最短路/建反图】 By cellur925
这么经典的题目,还是看了lyd的题解....唉难过。
一句话题意:在一张点有全都的图上找一条从1到n的路径,存在两个点p,q(p<q),使val[q]-val[p]最大。
给出的图是既有双向又有单向的混合图,考虑像普通的方法一样建图。除此之外,再在一个新邻接表中建原图的反图(边方向相反)。
为什么要这样做?
考虑分别自起点到终点和自终点到起点遍历,计算出f[]和d[],其中f[i]表示从1到i的路径中经过的最小的点权,d[i]表示从n到i的路径中经过的最大点权。(想一想,为什么?)
于是我们就可以枚举断点X,使d[x]-f[x]最大。保证了1能走到n,即路径的连贯(联通)性。
code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #define maxn 100090 6 #define maxm 500090 7 8 using namespace std; 9 10 int n,m,totp,totn,ans; 11 int headp[maxn],headn[maxn],val[maxn],f[maxn],d[maxn],vis[maxn]; 12 struct node{ 13 int to,next; 14 }; 15 node edge_posi[maxm*4],edge_nega[maxm*4]; 16 17 void add_posi(int x,int y) 18 { 19 edge_posi[++totp].to=y; 20 edge_posi[totp].next=headp[x]; 21 headp[x]=totp; 22 } 23 24 void add_nega(int x,int y) 25 { 26 edge_nega[++totn].to=y; 27 edge_nega[totn].next=headn[x]; 28 headn[x]=totn; 29 } 30 31 void spfa_posi() 32 { 33 queue<int>q; 34 memset(d,0x3f,sizeof(d)); 35 q.push(1);d[1]=val[1];vis[1]=1; 36 while(!q.empty()) 37 { 38 int x=q.front(); 39 q.pop();vis[x]=0; 40 for(int i=headp[x];i;i=edge_posi[i].next) 41 { 42 int y=edge_posi[i].to; 43 if(min(d[x],val[y])<d[y]) 44 { 45 d[y]=min(d[x],val[y]); 46 if(!vis[y]) q.push(y),vis[y]=1; 47 } 48 } 49 } 50 } 51 52 void spfa_nega() 53 { 54 queue<int>q; 55 memset(vis,0,sizeof(vis)); 56 memset(f,128,sizeof(f)); 57 q.push(n);d[n]=val[n];vis[n]=1; 58 while(!q.empty()) 59 { 60 int x=q.front(); 61 q.pop();vis[x]=0; 62 for(int i=headn[x];i;i=edge_nega[i].next) 63 { 64 int y=edge_nega[i].to; 65 if(max(f[x],val[y])>f[y]) 66 { 67 f[y]=max(f[x],val[y]); 68 if(!vis[y]) q.push(y),vis[y]=1; 69 } 70 } 71 } 72 } 73 74 int main() 75 { 76 scanf("%d%d",&n,&m); 77 for(int i=1;i<=n;i++) scanf("%d",&val[i]); 78 for(int i=1;i<=m;i++) 79 { 80 int x=0,y=0,opt=0; 81 scanf("%d%d%d",&x,&y,&opt); 82 if(opt==1) 83 { 84 add_posi(x,y); 85 add_nega(y,x); 86 } 87 else if(opt==2) 88 { 89 add_posi(x,y);add_posi(y,x); 90 add_nega(y,x);add_nega(x,y); 91 } 92 } 93 spfa_posi(); 94 spfa_nega(); 95 for(int i=1;i<=n;i++) 96 ans=max(ans,f[i]-d[i]); 97 printf("%d",ans); 98 return 0; 99 }
建反图的思想妙啊!
独立意志与自由思想是必须争的,且须以生死力争。