Codeforces864E-Fire-01背包DP+输出路径

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:传送门

 原题目描述在最下面。

 大火就要来了,你有n个物品,每个物品有其价值val,营救它所需要的时间tim和营救它的截至时间dl(超过这个时间它价值就为0)。问你能获得的最大价值。

思路:

 时间上限m为最大的截至时间。对于每件物品进行01背包DP,时间上下限为dltim。需要注意的事,要把所有的物品按照截至时间从小到大排序之后再DP,因为这样才能保证输出路径是正确的:这样才不会出现一个物品的营救时间再它截至时间之后的意外。

 对于输出路径我采用的是投机取巧方法,因为数据量很小,我直接用vector模拟的。输出路径这个东西再背包九讲的最后一部分有讲解。有需要可以取看下。

AC代码:
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;
const int N = 2e5+7;
const int INF = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
int n;
int val[105], tim[105], dl[105];
int dp[N];
vector<int> num[N];
struct lp{
  int v, t, d, id;
}cw[105];
bool cmpd(lp &a, lp &b){
  if(a.d != b.d)return a.d < b.d;
  return a.t < b.t;
}
int main(int argc, char const *argv[]){
  while(~scanf("%d", &n)){
    int m = 0;
    for(int i = 0; i <= n; ++i){
      num[i].clear();
    }
    for(int i = 1; i <= n; ++i){
      scanf("%d%d%d", &tim[i], &dl[i], &val[i]);
      m = max(m, dl[i]);
      cw[i].t = tim[i];cw[i].d = dl[i];cw[i].v = val[i];cw[i].id = i;
    }
    sort(cw + 1, cw + n + 1,cmpd);
    for(int i = 1; i <= n; ++i){
      tim[i] = cw[i].t;dl[i] = cw[i].d;val[i] = cw[i].v; 
    }
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= n; ++i){
      for(int j = dl[i] - 1; j >= tim[i]; --j){
        if(dp[j] < dp[j-tim[i]] + val[i]){
          dp[j] = dp[j-tim[i]] + val[i];
          num[j].clear();
          if(num[j-tim[i]].size()){
            for(auto x: num[j-tim[i]]){
              num[j].pb(x);
            }
          }
          num[j].pb(i);
        }
      }
    }
    int tmax = dp[m], p = m;
    for(int i = 1; i <= m; ++i){
      if(dp[i] > tmax){
        tmax = dp[i];
        p = i;
      }
    }
    m = p;
    printf("%d\n%d\n", dp[m], num[m].size());
    if(num[m].size()){
      printf("%d", cw[num[m][0]].id);;
      num[m].erase(num[m].begin());
      if(num[m].size()){
        for(auto x: num[m]){
          printf(" %d", cw[x].id);
        }
      }
      printf("\n");
    }
  }
  return 0;
}


原题目描述:

这里写图片描述

引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值