洛谷 P1073 最优贸易

题目传送门

解题思路:

先吐槽一下,因为本人太弱,狂肝4.5小时才A掉.要是在考场上不就废了

本题拿过来,很明显的贪心思路就是在每条1到n的路径上找最大和最小值,然后做差维护答案.

然而这样是不对,因为有可能对于一条路径,最小值在最大值后面出现,而这样这条路径上的答案明显不是它们的差值.

怎么办呢? 答案就是我们可以对于每个点,注意是每个"点",找1到这个点路径上的最小值,这个点到n的最大值,作差,这样至少对于这个点来说是最优解.

然后对于所有在1到n路径上的点的差维护最大值即可.

还有一个问题,我们怎样知道哪些点能从1到这个点然后再走到n呢?

当然从1走到当前点好办,直接遍历即可.那n呢,怎么办?其实只要反过来一想,把n想象成1,倒着便利一遍这个图就行.

所以,综上所述,只要正着跑一遍SPFA,反着跑一遍SPFA,然后维护答案即可.

注意:

1.因为要跑两遍SPFA,所以我们要正着,反着存两遍图

2.正着的SPFA是求最小值,而反着的SPFA是求最大值.

AC代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 #include<limits.h>
  7 
  8 using namespace std;
  9 
 10 queue<int > l1,l2;
 11 int a1,bn,n,m,a[100001],head[100001],tot,head1[100001],_tot,dist[100001],b[100001],dist1[100001]; 
 12 bool p[100001];
 13 struct kkk {
 14     int next,to,v;
 15 }e[500001],e1[500001];
 16 
 17 inline void add(int x,int y) {
 18     e[++tot].to = y;
 19     e[tot].next = head[x];
 20     e[tot].v = a[y];
 21     head[x] = tot;
 22 }
 23 
 24 inline void add1(int x,int y) {
 25     e1[++_tot].to = y;
 26     e1[_tot].next = head1[x];
 27     e1[tot].v = b[y];
 28     head1[x] = _tot;
 29 }
 30 
 31 inline void spfa_first_time(int s) {
 32     memset(dist,0x3f,sizeof(dist));
 33     memset(p,0,sizeof(p));
 34     dist[s] = a[s];
 35     l1.push(s);
 36     p[s] = true;
 37     while(!l1.empty()) {
 38         int u = l1.front();
 39         l1.pop();
 40         p[u] = false;
 41         for(int i = head[u];i != -1; i = e[i].next) {
 42             int end = e[i].to;
 43             int len = e[i].v;
 44             if(dist[u] < dist[end] || len < dist[end]) {
 45                 dist[end] = min(dist[u],len);
 46                 if(!p[end]) {
 47                     l1.push(end);
 48                     p[end] = 1;
 49                 }
 50             }    
 51         }
 52     }
 53 }
 54 
 55 inline void spfa_last_time(int s) {
 56     memset(dist1,0x80,sizeof(dist1));
 57     memset(p,0,sizeof(p));
 58     dist1[s] = b[s];
 59     l2.push(s);
 60     p[s] = true;
 61     while(!l2.empty()) {
 62         int u = l2.front();
 63         l2.pop();
 64         p[u] = false;
 65         for(int i = head1[u];i != -1; i = e1[i].next) {
 66             int end = e1[i].to;
 67                int len = e1[i].v;
 68             if(dist1[u] > dist1[end] || len > dist1[end]) {
 69                 dist1[end] = max(dist1[u],len);
 70             if(!p[end]) {
 71                 l2.push(end);
 72                 p[end] = 1;
 73             }}
 74         }
 75     }
 76 }
 77 
 78 bool cmp(int q,int r) {
 79     return q > r;
 80 }
 81 
 82 int main() {
 83     memset(head,-1,sizeof(head));
 84     memset(head1,-1,sizeof(head1));
 85     scanf("%d%d",&n,&m);
 86     for(int i = 1;i <= n; i++) {
 87         scanf("%d",&a[i]);
 88         b[i] = a[i];
 89     }
 90     for(int i = 1;i <= m; i++) {
 91         int x,y,z;
 92         scanf("%d%d%d",&x,&y,&z);
 93         if(z == 1) {
 94             add(x,y);
 95             add1(y,x);
 96         }
 97         if(z == 2) {
 98             add(x,y);
 99             add(y,x);
100             add1(x,y);
101             add1(y,x);
102         }
103     }
104     spfa_first_time(1);//正着 
105     spfa_last_time(n);//反着 
106     for(int i = 1;i <= n; i++) 
107         a[i] = dist1[i] - dist[i];
108     sort(a+1,a+1+n,cmp);
109     if(a[1] <= 0 || a[1] >= 0x3f3f3f3f) printf("0");
110     else printf("%d",a[1]);
111     return 0;
112 }

//NOIP2009提高 T3

 

posted @ 2019-08-05 22:51  Mr^Simon  阅读(202)  评论(1编辑  收藏  举报