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背包真的很简单。

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号