SSL 1276 石子合并 (动态规划 01背包)
动 规 永 远 的 基 础 — — 01 背 包 问 题 动规永远的基础——01背包问题 动规永远的基础——01背包问题
题目大意:
你有N个石头,质量分别为W1,W2,W3…WN. (W<=100000) 现在需要你将石头分为两堆,使两堆质量的差为最小。
解题思路:
第一眼看到这道题,你会想起爆搜,它也确实能过,但是我们不那么做,为什么?
因为
搜索是粗暴的咆哮,而DP是自由与骄傲的吟唱
但是,这题怎么用DP做呢?状态是什么?阶段是什么?我们依然一无所知。
其实我们可以这么想,让两堆石头质量差最小,其实就是一个选与不选的过程,这是什么DP?是那个永远的神,拥有变化万千的算法——01背包DP啊!
那01背包到底是什么呢?我们来详细的聊聊……
再看看基础的01背包例题吧~~~
知道了可以用01背包来做,算法中的 物品价值 是什么也知道了,物品质量 是什么也知道了,但背包的容量到底多大啊?题目中的“使两堆质量差值最小”似乎没有明确给出啊!!
观察题目,我们知道了我们要求的是两堆石头的最小差值,那么最小差值的本质是什么?就是其中一堆石头减去另一堆石头的值,也就是说这题实际上就是让我们求其中的一堆石头该怎么安排——思路似乎变明朗了!
如何安排石头让差值最小呢?就是让其中的一堆石头的质量尽量接近所有石头的总质量之和的
1
2
\frac1 2
21!
有了这个思路,问题得以转换,让选取的变量尽量接近而不超过一个固定的常量,这不就是01背包算法吗?
设
V
V
V为所有石头的总质量之和。
石头有选与不选两种转态,有一个容量为
1
2
\frac1 2
21V的背包,如何在不超过容量的情况下装最重的石头
题解看到这里,你就会发现,这就是一道最普通的01背包题。
状态转移方程: d p v = m a x ( d p v , d p v − w i + a i ) dp_v=max(dp_v,dp_{v-w_i}+a_i) dpv=max(dpv,dpv−wi+ai)
也不多说了,重点是将问题层层转换为最原始的状态,只要明白了,任何算法都可以很简单
CODE
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int t=0,m,a[110],w[110],ans;
int dp[1000001];
void input()
{
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>w[i]; //单个石头质量
t+=w[i]; //用T表示石头总质量
}
}
void DP() //标准01背包 DP 代码
{
for(int i=1;i<=m;i++)
{
for(int j=t/2;j>=w[i];j--)
{
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
ans=max(ans,dp[j]);
}
}
cout<<(t-ans)-ans; //输出两堆石头的差值
}
int main()
{
input();
DP();
return 0;
}
总结:
01背包 问题的最大特点就是多变。因此,01背包问题最大的难点,就是你能否将一个 畸形的01背包问题 转换为你所学过的,你所认识的那个样子,将一个最不像01背包的题目,用01背包的做法AC。
只要学会了题目之间的变通,01背包真的很简单。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!