专栏文章

题解:Robot Customize

AT_abc431_d题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mina1mwp
此快照首次捕获于
2025/12/01 23:01
3 个月前
此快照最后确认于
2025/12/01 23:01
3 个月前
查看原文

Robot Customize

题目大意

我们需要将 NN 种部件分配到机器人的头部或身体上,使得:
  • 头部总重量不超过身体总重量(防止机器人倒下);
  • 所有部件的幸福感总和最大化。
而每个部件有三种属性:
  • 重量 WiW_i
  • 连接头部的幸福感 HiH_i
  • 连接身体的幸福感 BiB_i

关键思路

初看这个问题,我会立马想到贪心策略,比如按某种优先级排序后分配部件。但仔细分析会发现,部件的重量和幸福感之间没有简单的单调关系,贪心法无法保证最优解。
我们可以这样重新思考问题:
  1. 初始状态假设所有部件都连接到身体上(因为头轻脚重一定不会摔倒),此时总幸福感为 i=1NBi\sum_{i=1}^N B_i
  2. 部件移动:如果将一个部件从身体移动到头部:
    • 幸福感变化HiBiH_i - B_i(可能为正或负),
    • 重量变化:头部增加 WiW_i,身体减少 WiW_i
    • 净重量影响:头部相对于身体增加了 2×Wi2 \times W_i
  3. 约束条件转换:头部重量 \le 身体重量:
    • 初始:头部重量 =0=0,身体重量 == 总重量 T=i=1NWiT = \sum_{i=1}^N W_i
    • 移动一些部件后:头部重量 =S=S,身体重量 =TS=T-S
    • 约束条件STSS \le T - S,则 2×ST2 \times S \le T
  4. 问题本质:选择一部分部件连接到头部,使得:
    • 头部总重量 2×ST2 \times S \le T
    • 幸福感增加值 HiBi\sum H_i-B_i 最大化。
看到这,相信大家都懂了:这正好是一个 0101 背包问题
  • 物品:可以移动到头部的部件(仅考虑 Hi>BiH_i > B_i 的部件,因为只有这些移动才会增加幸福感);
  • 重量2×Wi2 \times W_i
  • 价值HiBiH_i - B_i
  • 背包容量:总重量 TT

代码详解

CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,w[505],v[505],len,t,now,lst,ans;
unordered_map<int,int> dp[5]; //使用unordered_map优化时间,再开一个滚动数组,只存储可能的状态(不然要TLE)
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		int nw,nh,nb;
		cin>>nw>>nh>>nb;
		t+=nw;//计算总重量
        ans+=nb; //初始状态:所有部件都连身体
        //只考虑那些连接到头部能增加幸福感的部件
		if(nh>nb){
			len++;
			w[len]=nw*2; //移动部件到头部会使头部相对重量增加 2*Wi
			v[len]=nh-nb; //移动部件到头部带来的幸福感增加值
		}
	}
    //直接跑一次0-1背包模板即可
	for(int i=1;i<=len;i++){
        //滚动数组优化:交替使用两个unordered_map
		if(i%2==0) now=2,lst=1;
		else now=1,lst=2;
		for(int j=1;j<=t;j++){
			if(j<w[i]) dp[now][j]=dp[lst][j];
			else dp[now][j]=max(dp[lst][j],dp[lst][j-w[i]]+v[i]);
		}		
	}
	ans+=dp[now][t]; //最终结果 = 初始幸福感 + 通过移动部件能增加的最大幸福感
	cout<<ans;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...