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

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

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

代码:

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include<set>
  8 #include
  9 #include
 10 #include
 11 #include<string>
 12 #include
 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 ) {
 64         if (!dfn[i]) {
 65             tarjan(i);
 66         }
 67     }
 68     for (int u = 1; 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 10; i++) G[i].clear();
102     for (int i = 0; i 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 ) {
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 ) {
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 }

永远热爱,永远向着光。

Original: https://www.cnblogs.com/wabi/p/16537313.html
Author: Kyrizer_W
Title: P1073 [NOIP2009 提高组] 最优贸易(tarjan缩点+dp)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/587872/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球