[SPFA][NOIP2009T3][jzyzoj1219]最佳贸易

  犯了个SB错误。。。题面太长自己百度。。。

  从题意可以看出来我们需要求到的值是买入的最小值减去卖出的最大值。

  第一遍看的时候觉得哇这个题好难啊,100000个点500000个边怎么解?

  如果用dijkstra的话好像不能同时求出来最大值和最小值,而且复杂度是m*n,会超时,所以要考虑到SPFA。

  但是用SPFA也不能一次枚举同时求出最大值和最小值。

  1次不够,就2次。

  仔细想想的话买和卖可以将整张图分为两个阶段,在第一个阶段中我们从1开始进行SPFA,更新从1到n的路径上所有的买入的最小值,这样我们就有从1到n的所有买入最小值了。

  最大值还要从1开始做SPFA吗?

  我们在阶段1中所求得的买入最小值,这里指的是从1到i中的最佳值,如果还是从1开始遍历的话,我们求得的还是1到i的路径中的最佳值,但事实上卖出的时候所求的最佳值应该是从i到n的,所以从1开始做SPFA是无法得出正解的。

  因此我们可以得出,卖出的最大值一定是应当以n为起点做SPFA的。

  但是题中的边有双向也有单向,这时候需要我们在建正向图的时候同时建一个反向图,在进行第一阶段的SPFA时用正向图,进行第二阶段的SPFA时用反向图,然后从1到n将所有点遍历一遍就能得到最优解。代码如下: 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 struct edge{
  7     int y,ne;
  8 }edge1[1000010],edge2[1000010];
  9 int head1[100010],head2[100010],n,m,price,buy[100010],sell[100010],len1=0,len2=0,v[100010],queue[1000010];
 10 bool vis[100010];
 11 inline void addedge1(int x,int y)
 12 {edge1[++len1].y=y;    edge1[len1].ne=head1[x];    head1[x]=len1;}
 13 
 14 inline void addedge2(int x,int y)
 15 {edge2[++len2].y=y;    edge2[len2].ne=head2[x];    head2[x]=len2;}
 16 
 17 void init()
 18 {
 19     memset(head1,-1,sizeof(head1));
 20     memset(head2,-1,sizeof(head2));
 21     memset(buy,0x3f,sizeof(buy));
 22     memset(sell,0,sizeof(sell));
 23     scanf("%d%d",&n,&m);
 24     for (int i=1;i<=n;i++)
 25         scanf("%d",&v[i]);
 26     int x,y,z;
 27     for (int i=1;i<=m;i++)
 28     {
 29         scanf("%d%d%d",&x,&y,&z);
 30         addedge1(x,y);    addedge2(y,x);
 31         if (z==2)    {addedge1(y,x);    addedge2(x,y);}
 32     }
 33 }
 34 
 35 void spfa1(int s)
 36 {
 37     int head=0,tail=1;
 38     memset(vis,false,sizeof(vis));
 39     queue[1]=s;    buy[1]=v[s];    vis[s]=true;
 40     while(head<tail)
 41     {
 42         int tn=queue[++head];
 43         vis[tn]=false;
 44         int te=head1[tn];
 45         for (int i=te;i!=-1;i=edge1[i].ne)
 46         {
 47             int tmp=edge1[i].y;
 48             int minn=min(buy[tn],v[tmp]);
 49             if (buy[tmp]>minn)
 50             {
 51                 buy[tmp]=minn;
 52                 if (!vis[tmp])
 53                 {
 54                     vis[tmp]=true;
 55                     queue[++tail]=tmp;
 56                 }
 57             }
 58         }
 59     }
 60 }
 61 
 62 void spfa2(int s)
 63 {
 64     memset(vis,false,sizeof(vis));
 65     int head=0,tail=1;
 66     queue[1]=s;    sell[s]=v[s];    vis[s]=true;
 67     while (head<tail)
 68     {
 69         int tn=queue[++head];
 70         int te=head2[tn];
 71         vis[tn]=false;
 72         for (int i=te;i!=-1;i=edge2[i].ne)
 73         {
 74             int tmp=edge2[i].y;
 75             int maxx=max(sell[tn],v[tmp]);
 76             if (sell[tmp]<maxx)
 77             {
 78                 sell[tmp]=maxx;
 79                 if (!vis[tmp])
 80                 {
 81                     queue[++tail]=tmp;
 82                     vis[tmp]=true;
 83                 }
 84             }
 85         }
 86     }
 87 }
 88 int main()
 89 {
 90     init();
 91     spfa1(1);
 92     spfa2(n);
 93     int maxx=0;
 94     for (int i=1;i<=n;i++)
 95     {
 96         maxx=max(maxx,sell[i]-buy[i]);
 97     }
 98     printf("%d
",maxx);
 99     return 0;
100 }
AC代码

原文地址:https://www.cnblogs.com/hinanawitenshi/p/6558965.html