zoukankan      html  css  js  c++  java
  • 洛谷 P1073 最优贸易 & [NOIP2009提高组](反向最短路)

    传送门


    解题思路

    很长的题,实际上在一个有向图(点有点权)中求一个从起点1到终点n的路径,使得这条路径上点权最大的点与点权最小的点的差值最大(要求必须从点权较小的点能够走到点权较大的点)。

    ——最短路??

    ——不像呀。

    (可是洛谷标签上写着呀)

    就是一个写起来像最短路的一个图中的dp。

    我们用dis1[i]表示从1号点到第i号点的路径上的最小值,用dis2[i]表示从i号点到第n号点的最大值,最后只需要找出最大的(dis2[i]-dis1[i])即可。

    怎么求dis2呢?这里有一种方法——建反图。

    建反图就是把每一条有向边反过来,例如原来是u-->v,现在变成了v-->u。

    然后从n开始,跑一遍n到各个点的最短路,求出dis2数组。

    对于dis数组,dis[i的儿子k]=dis[i],v[k](k号点本身的数值),dis[k]中的最小值/最大值。

    用dijkstra或者spfa跑一遍图就可以了。

    当年,spfa还没有死去。

    AC代码

     1 #include<iostream>
     2 #include<queue>
     3 #include<cstdio>
     4 #include<cstring>
     5 using namespace std;
     6 const int maxn=100005;
     7 const int maxm=1000005;//注意有可能是双向边,所以要开两倍的数组。 
     8 int n,m,p1[maxn],p2[maxn],cnt1,cnt2,vis[maxn],dis1[maxn],dis2[maxn],ans,v[maxn];
     9 struct edge{
    10     int v,next;
    11 }e1[maxm],e2[maxm];            //两个图 
    12 void insert1(int u,int v){    //两个insert 
    13     cnt1++;
    14     e1[cnt1].v=v;
    15     e1[cnt1].next=p1[u];
    16     p1[u]=cnt1;    
    17 }
    18 void insert2(int u,int v){
    19     cnt2++;
    20     e2[cnt2].v=v;
    21     e2[cnt2].next=p2[u];
    22     p2[u]=cnt2;    
    23 }
    24 struct node{
    25     int num,len;
    26 };
    27 bool operator < (node a,node b){
    28     return a.len>b.len;
    29 } 
    30 priority_queue<node> q1,q2;
    31 void dijkstra1(){            //两个dijkstra 
    32     memset(vis,0,sizeof(vis));
    33     memset(dis1,0x3f,sizeof(dis1));
    34     dis1[1]=v[1];
    35     node nd;
    36     nd.len=v[1];
    37     nd.num=1;
    38     q1.push(nd);
    39     while(!q1.empty()){
    40         node u=q1.top();
    41         q1.pop();
    42         if(vis[u.num]) continue;
    43         vis[u.num]=1;
    44         for(int i=p1[u.num];i!=-1;i=e1[i].next){
    45             dis1[e1[i].v]=min(min(dis1[e1[i].v],u.len),v[e1[i].v]);//算是个小的dp吧 
    46             node xin;
    47             xin.num=e1[i].v;
    48             xin.len=dis1[e1[i].v];
    49             q1.push(xin);
    50         }
    51     }
    52 }
    53 void dijkstra2(){
    54     memset(vis,0,sizeof(vis));
    55     memset(dis2,-0x3f,sizeof(dis2));
    56     dis2[n]=v[n];
    57     node nd;
    58     nd.len=v[n];
    59     nd.num=n;
    60     q2.push(nd);
    61     while(!q2.empty()){
    62         node u=q2.top();
    63         q2.pop();
    64         if(vis[u.num]) continue;
    65         vis[u.num]=1;
    66         for(int i=p2[u.num];i!=-1;i=e2[i].next){
    67             dis2[e2[i].v]=max(max(dis2[e2[i].v],u.len),v[e2[i].v]);
    68             node xin;
    69             xin.num=e2[i].v;
    70             xin.len=dis2[e2[i].v];
    71             q2.push(xin);
    72         }
    73     }
    74 }
    75 int main(){
    76     cin>>n>>m;
    77     memset(p1,-1,sizeof(p1));
    78     memset(p2,-1,sizeof(p2));
    79     for(int i=1;i<=n;i++) cin>>v[i];
    80     for(int i=1;i<=m;i++){
    81         int x,y,z;
    82         scanf("%d%d%d",&x,&y,&z);
    83         if(z==1){
    84             insert1(x,y);
    85             insert2(y,x);
    86         }else{
    87             insert1(x,y);
    88             insert1(y,x);
    89             insert2(x,y);
    90             insert2(y,x);
    91         }
    92     }
    93     dijkstra1();
    94     dijkstra2();
    95     for(int i=1;i<=n;i++) ans=max(ans,dis2[i]-dis1[i]);//求出答案 
    96     cout<<ans;
    97     return 0; 
    98 }

     //NOIP2009提高组t3

    //好困啊,zzz

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/11623837.html
Copyright © 2011-2022 走看看