2 条题解

  • 0
    @ 2025-11-1 17:19:53

    邻接表:

    #include <bits/stdc++.h>
    using namespace std;
    
    /*
      题意总结:
      给定 n 个地窖(编号 1~n),每个地窖中有一定数量的地雷。
      连接关系为有向边 xi → yi,且 xi < yi(无环 DAG)。
      目标:选择一条从任意起点出发、顺着有向边往下走的路径,
            使得路径上地雷总数最大,并输出路径顺序和最大值。
    */
    
    /*
      DP 定义:
      dp[i] 表示「以第 i 个地窖为终点」所能挖到的地雷总数的最大值。
      转移方程:
          dp[i] = max( dp[j] + w[i] ),其中存在边 j → i。
      初始化:
          dp[i] = w[i](即只挖自己,不依赖其他地窖)
    */
    
    void print_path(int k, const vector<int>& pre) {
        if (k == 0) return; // 递归终止条件
        print_path(pre[k], pre);
        if (pre[k] == 0)
            cout << k;
        else
            cout << "-" << k;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        int n;
        cin >> n; // 输入地窖个数
    
        vector<int> w(n + 1);    // w[i]: 第 i 个地窖的地雷数
        vector<int> dp(n + 1);   // dp[i]: 以 i 为终点的最大可挖地雷数
        vector<int> pre(n + 1);  // pre[i]: 记录 dp[i] 的最优前驱(用于路径重建)
        vector<vector<int>> g(n + 1); // 邻接表表示有向边
    
        // 输入每个地窖的地雷数
        for (int i = 1; i <= n; ++i) {
            cin >> w[i];
            dp[i] = w[i]; // 初始状态:只挖当前地窖
        }
    
        // 输入有向边(xi → yi)
        while (true) {
            int x, y;
            cin >> x >> y;
            if (x == 0 && y == 0) break;
            g[y].push_back(x); // 存反向边方便 DP:找能到 y 的所有 j
        }
    
        int max_val = LLONG_MIN; // 当前最大挖雷总数
        int end_node = 0;        // 最优路径的终点
    
        // 因为 xi < yi,节点编号本身就是拓扑序,可直接顺序 DP
        for (int i = 1; i <= n; ++i) {
            // 枚举所有能到达 i 的前驱 j
            for (int j : g[i]) {
                if (dp[j] + w[i] > dp[i]) {
                    dp[i] = dp[j] + w[i];
                    pre[i] = j; // 记录最优前驱
                }
            }
            // 更新当前最大值与路径终点
            if (dp[i] > max_val) {
                max_val = dp[i];
                end_node = i;
            }
        }
    
        // 输出最优路径
        print_path(end_node, pre);
        cout << '\n' << max_val << '\n';
    
        return 0;
    }
    
    
    • 0
      @ 2025-11-1 17:19:30

      邻接矩阵写法:

      #include <bits/stdc++.h>
      using namespace std;
      
      /*
        题意(简述):
        有 n 个地窖(1..n),每个地窖有地雷数 w[i]。有向边 xi->yi(且 xi<yi,无环)。
        从任意地窖出发,沿边一直向后挖(只能走一条路径),使路径上地雷总和最大。
        要输出:一条最优路径(用 '-' 连接)以及最大地雷数。
      
        DP 定义:
        dp[i] 表示「以 i 为终点」所能挖到的地雷总数的最大值。
        状态转移:
            dp[i] = max( dp[j] + w[i] ),对所有存在边 j->i 的 j。
        初始化:
            dp[i] = w[i](只挖自己)
        路径重建:
            pre[i] 记录使 dp[i] 最优的前驱 j(若没有则为 0)。
      */
      
      void print_path(int x, const vector<int>& pre) {
          if (x == 0) return;
          print_path(pre[x], pre);
          if (pre[x] == 0) cout << x;
          else cout << "-" << x;
      }
      
      int main() {
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
      
          int n;
          if (!(cin >> n)) return 0;
      
          // 读入每个地窖的地雷数
          vector<long long> w(n + 1), dp(n + 1), pre(n + 1, 0);
      
          for (int i = 1; i <= n; ++i) {
              cin >> w[i];
              dp[i] = w[i];   // 初始化:只挖自己
          }
      
          // 邻接矩阵 g[u][v] = 1 表示 u -> v 有边(保证 u < v)
          vector<vector<int>> g(n + 1, vector<int>(n + 1, 0));
          while (true) {
              int x, y;
              if (!(cin >> x >> y)) return 0;
              if (x == 0 && y == 0) break;
              if (1 <= x && x <= n && 1 <= y && y <= n) {
                  g[x][y] = 1;
              }
          }
      
          // 因为题目保证边都是从小编号指向大编号(拓扑序即 1..n),
          // 我们按 i 从小到大做 DP,枚举所有可能的前驱 j。
          long long best = LLONG_MIN;
          int end_node = 0;
      
          for (int i = 1; i <= n; ++i) {
              // 枚举所有 j,看是否存在 j->i 的边;若存在则尝试转移
              for (int j = 1; j <= n; ++j) {
                  if (g[j][i]) { // j -> i
                      if (dp[j] + w[i] > dp[i]) {
                          dp[i] = dp[j] + w[i];
                          pre[i] = j;        // 记录最优前驱
                      }
                  }
              }
              if (dp[i] > best) {
                  best = dp[i];
                  end_node = i;
              }
          }
      
          // 输出路径与最大值
          print_path(end_node, pre);
          cout << "\n" << best << "\n";
          return 0;
      }
      
      
      • 1

      信息

      ID
      740
      时间
      1000ms
      内存
      256MiB
      难度
      6
      标签
      递交数
      23
      已通过
      11
      上传者