P1073 [NOIP2009 提高组] 最优贸易(tarjan缩点+dp)

题目传送门:https://www.luogu.com.cn/problem/P1073

思路:首先,我们目的是想要在图上dp求最优的路线,但是原图上会存在环,那么我们就要先通过tarjan缩点,将所有环缩成一个点,同时,记录每个点的最大值和最小值,缩点得到DAG后,我们可以在DAG上进行dp,每次转移有三种方式,一是保留上一个点的dp值,二是求得目前所在点的值,三是这个点本身的dp值,三者取最大就ok了。还要注意的是,在建DAG图的时候,要记录每个点的入度,在之后的dp过程中,每一个点在全部走到的时候,才能压入队列,进行更新操作,保证dp内的值是最优的,也就是无后效性。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<map>
  6 #include<queue>
  7 #include<set>
  8 #include<cmath>
  9 #include<list>
 10 #include<cstring>
 11 #include<string>
 12 #include<stack>
 13 #define ll long long
 14 #define ull unsigned long long
 15 #define inf 0x3f3f3f3f
 16 #define inff 0x7fffffff
 17 using namespace std;
 18 const int N = 100000 + 10;
 19 
 20 int n, m;
 21 int dfn[N], low[N];
 22 int dfncnt, scccnt;
 23 stack<int>st;
 24 bool ins[N];
 25 int scc[N];
 26 int w[N];
 27 int in[N];
 28 
 29 int dp[N];
 30 int Max[N], Min[N];
 31 
 32 vector<int>G[N];
 33 vector<int>DAG[N];
 34 
 35 void tarjan(int u) {
 36     dfn[u] = ++dfncnt;
 37     low[u] = dfncnt;
 38     st.push(u);
 39     ins[u] = true;
 40     for (int i = 0; i < G[u].size(); i++) {
 41         int v = G[u][i];
 42         if (!dfn[v]) {
 43             tarjan(v);
 44             low[u] = min(low[u], low[v]);
 45         }
 46         else if (ins[v]) {
 47             low[u] = min(low[u], dfn[v]);
 48         }
 49     }
 50     if (dfn[u] == low[u]) {
 51         int v;
 52         ++scccnt;
 53         do {
 54             v = st.top();
 55             st.pop();
 56             ins[v] = false;
 57             scc[v] = scccnt;
 58         } while (u != v);
 59     }
 60 }
 61 
 62 void getdag() {
 63     for (int i = 1; i <= n; i++) {
 64         if (!dfn[i]) {
 65             tarjan(i);
 66         }
 67     }
 68     for (int u = 1; u <= n; u++) {
 69         for (int j = 0; j < G[u].size(); j++) {
 70             int v = G[u][j];
 71             if (scc[u] != scc[v]) {
 72                 DAG[scc[u]].push_back(scc[v]);
 73                 in[scc[v]]++;
 74             }
 75         }
 76     }
 77 }
 78 
 79 queue<int>q;
 80 void dagdp(int s) {
 81 
 82     q.push(s);
 83     dp[s] = max(dp[s], Max[s] - Min[s]);
 84     while (!q.empty()) {
 85 
 86         int u = q.front();
 87         q.pop();
 88         for (int i = 0; i < DAG[u].size(); i++) {
 89             int v = DAG[u][i];
 90             in[v]--;
 91             Min[v] = min(Min[v], Min[u]);
 92             dp[v] = max(dp[v], max(dp[u], Max[v] - Min[v]));
 93             if (!in[v]) q.push(v);
 94         }
 95 
 96     }
 97 
 98 }
 99 
100 void init() {
101     for (int i = 0; i <= N - 10; i++) G[i].clear();
102     for (int i = 0; i <= N - 10; i++) DAG[i].clear();
103     memset(dp, 0, sizeof(dp));
104     memset(scc, 0, sizeof(scc));
105     memset(ins, 0, sizeof(ins));
106     memset(dfn, 0, sizeof(dfn));
107     memset(low, 0, sizeof(low));
108     dfncnt = 0, scccnt = 0;
109     memset(Min, 0x3f, sizeof(Min));
110 }
111 
112 int main() {
113 
114     ios::sync_with_stdio(false);
115     cin.tie(0), cout.tie(0);
116     //int n, m;
117     cin >> n >> m;
118     init();
119     for (int i = 1; i <= n; i++) {
120         cin >> w[i];
121     }
122     for (; m; --m) {
123         int u, v, c;
124         cin >> u >> v >> c;
125         G[u].push_back(v);
126         if (c == 2) G[v].push_back(u);
127     }
128     getdag();
129     for (int i = 1; i <= n; i++) {
130         Max[scc[i]] = max(Max[scc[i]], w[i]);
131         Min[scc[i]] = min(Min[scc[i]], w[i]);
132     }
133     dagdp(scc[1]);
134     cout << dp[scc[n]] << "\n";
135 
136     return 0;
137 }

 

 
 
posted @ 2022-07-31 16:02  Keyzee  阅读(55)  评论(0编辑  收藏  举报