• 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

    建反图的思想妙啊!

  • 相关阅读:
    【springboot】 springboot整合quartz实现定时任务
    Map集合的四种遍历方式
    WCF自引用和循环引用导致的序列化问题
    c#反射
    小助手配置文件列表页
    WPF数据绑定(ItemTemplate和DataTemplate)
    TankMapData
    手机qq协议做的第三方qq软件
    WPF MVVM模式学习
    小助手(应用盒子之我的实现思路及示例程序)
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9478581.html
Copyright © 2020-2023  润新知