zoukankan      html  css  js  c++  java
  • NOIP2009T3最优贸易(Dfs + spfa)

    洛谷传送门

    看到这个题,原本想先从后往前dfs,求出能到终点的点,再在这些点里从前往后spfa,用一条边上的两个城市的商品价格的差来作边权,实施过后,发现图中既有负边权,又有回路,以及各种奇奇怪怪的东西。说实话我连样例都没过,然后提交一下试试,得了10分。

    然而我发现,要求赚最多钱,就是到那个点的路径上的最大价格 - 最小价格。

    两边dfs——

    最小价格可以从前往后搜来算。

    最大价格可以从后往前搜来算。

    最后枚举一边所有点maxx - minn的最大值就好。

    说出来你可能不信,我是看的题解。

    ——代码

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <iostream>
    
    using namespace std;
    
    int n, m, cnt1, cnt2, ans;
    int a[100001], next1[1000001], to1[1000001], head1[100001], next2[1000001], to2[1000001],
        head2[100001], maxx[100001], minn[100001];
    
    inline void add1(int x, int y)
    {
        to1[cnt1] = y;
        next1[cnt1] = head1[x];
        head1[x] = cnt1++;
    }
    
    inline void add2(int x, int y)
    {
        to2[cnt2] = y;
        next2[cnt2] = head2[x];
        head2[x] = cnt2++;
    }
    
    inline void dfs2(int u, int k)
    {
        int i, v;
        maxx[u] = max(maxx[u], k);
        for(i = head2[u]; i != -1; i = next2[i])
        {
            v = to2[i];
            if(maxx[v] < k) dfs2(v, max(k, a[v]));
        }
    }
    
    inline void dfs1(int u, int k)
    {
        int i, v;
        minn[u] = min(minn[u], k);
        for(i = head1[u]; i != -1; i = next1[i])
        {
            v = to1[i];
            if(minn[v] > k) dfs1(v, min(k, a[v]));
        }
    }
    
    int main()
    {
        int i, j, x, y, z;
        memset(head1, -1, sizeof(head1));
        memset(head2, -1, sizeof(head2));
        scanf("%d %d", &n, &m);
        for(i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            maxx[i] = -1e9;
            minn[i] = 1e9;
        }
        for(i = 1; i <= m; i++)
        {
            scanf("%d %d %d", &x, &y, &z);
            if(z == 2)
            {
                add1(x, y);
                add1(y, x);
                add2(x, y);
                add2(y, x);
            }
            else
            {
                add1(x, y);
                add2(y, x);
            }
        }
        dfs1(1, a[1]);
        dfs2(n, a[n]);
        for(i = 1; i <= n; i++) ans = max(ans, maxx[i] - minn[i]);
        printf("%d", ans);
        return 0;
    }
    View Code

     其中dfs不用设置vis来记录是否被访问过,因为有双向道路,所以走到一个点有可能会返回来,所以进行深搜的判断标准是目标点(姑且这么说吧)的最大最小值小于或大于当前点的最大最小值。这样即使走到后面的点,发现前面的点需要修改,也可以改回去。

    也可以用 spfa ,改变一下松弛操作,dis 数组表示到当前点的路径上买入的最小值,最后统计一遍就行。

    ——代码

     1 #include <queue>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 
     6 using namespace std;
     7 
     8 const int MAXN = 200001;
     9 int n, m, cnt, cnt1, ans;
    10 int a[MAXN], head[MAXN], to[MAXN], next[MAXN], head1[MAXN], to1[MAXN], next1[MAXN], dis[MAXN];
    11 bool b[MAXN], vis[MAXN];
    12 queue <int> q;
    13 
    14 inline void add(int x, int y)
    15 {
    16     to[cnt] = y;
    17     next[cnt] = head[x];
    18     head[x] = cnt++;
    19 }
    20 
    21 inline void add1(int x, int y)
    22 {
    23     to1[cnt1] = y;
    24     next1[cnt1] = head1[x];
    25     head1[x] = cnt1++;
    26 }
    27 
    28 inline void dfs(int u)
    29 {
    30     int i, v;
    31     b[u] = 1;
    32     for(i = head1[u]; i != -1; i = next1[i])
    33     {
    34         v = to1[i];
    35         if(!b[v]) dfs(v);
    36     }
    37 }
    38 
    39 inline void spfa(int u)
    40 {
    41     int i, v;
    42     memset(dis, 127 / 3, sizeof(dis));
    43     q.push(u);
    44     dis[u] = a[u];
    45     while(!q.empty())
    46     {
    47         u = q.front();
    48         q.pop();
    49         vis[u] = 0;
    50         for(i = head[u]; i != -1; i = next[i])
    51         {
    52             v = to[i];
    53             if(dis[v] > min(dis[u], a[v]) && b[v])
    54             {
    55                 dis[v] = min(dis[u], a[v]);
    56                 if(!vis[v])
    57                 {
    58                     q.push(v);
    59                     vis[v] = 1;
    60                 }
    61             }
    62         }
    63     }
    64 }
    65 
    66 int main()
    67 {
    68     int i, j, x, y, z;
    69     scanf("%d %d", &n, &m);
    70     for(i = 1; i <= n; i++) scanf("%d", &a[i]);
    71     memset(head, -1, sizeof(head));
    72     memset(head1, -1, sizeof(head1));
    73     for(i = 1; i <= m; i++)
    74     {
    75         scanf("%d %d %d", &x, &y, &z);
    76         if(z == 1)
    77         {
    78             add(x, y);
    79             add1(y, x);
    80         }
    81         else
    82         {
    83             add(x, y);
    84             add(y, x);
    85             add1(x, y);
    86             add1(y, x);
    87         }
    88     }
    89     dfs(n);
    90     spfa(1);
    91     for(i = 1; i <= n; i++)
    92         if(b[i])
    93             ans = max(ans, a[i] - dis[i]);
    94     printf("%d", ans);
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    植物:吊兰
    植物:文竹
    理论:混沌理论
    图书-数学:《数学之美》
    调味品:味精
    linux查看文件大小df-du
    linux防火墙开启-关闭
    tomcat端口号、日志、启停
    chmod
    jdk-tomcat环境变量设置
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6679748.html
Copyright © 2011-2022 走看看