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

  • 相关阅读:
    Modbus软件开发实战指南 之 开发自己的Modbus Poll工具
    Divide Two Integers-不用'/' '*' '%'操作实现整数的除法
    用最少的砝码称出1到100克的物品
    Binary Tree Inorder Traversal-非递归实现中序遍历二叉树
    leetcode Word Break-单词划分
    位运算题目
    leetcode Single Number II
    leetcode 4Sum
    leetcode 3Sum Closest
    Unique Binary Search Trees-计算表示相同序列的不同BST个数
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/11623837.html
Copyright © 2011-2022 走看看