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 }
View Code

建反图的思想妙啊!

posted @ 2018-08-14 23:02  cellur925&Chemist  阅读(216)  评论(0编辑  收藏  举报