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
原文地址:https://www.cnblogs.com/zhenghaotian/p/6679748.html