算法 - 动态规划 - 状态转移+01背包问题
在做拼多多C++岗的笔试题时候,第三题的题目是:
有N个货物(0<=N<=1024),每个货物的重量是W(100<=W<=300)。如果每辆车最多的载重为300,请问最少需要多少辆车才能运输所有货物。
开始尝试用贪心算法来求,先将货物从小到大排序,然后每次取最后最大的数装载,装不上时再取前面最小的数装载。这种贪心算法通过率为55%,原因是有些数据使用贪心算法行不通,比如:100 100 100 140 150 150 160。
后来自己下来思考这道题目,发现POJ的2923(Relocation)跟这道题大同小异:
有个人需要搬家,有N件物品,给个物品的重量是 w[i] 然后又两个车,每个车的载重量分别是C1和C2,求最少需要运输多少次才能把这些物品全部运输完毕。
输入输出:
Sample Input:
2 - - 例子个数
6 12 13 - - N个物品,第一辆车的容量v1,第二辆车的容量v2
3 9 13 3 10 11 - - N个物品的单个容量
7 1 100
1 2 33 50 50 67 98
Sample Output:
Scenario #1: - - 第一个例子
2 - - 两趟
Scenario #2: - - 第二个例子
3 - - 三趟
POJ的2923(Relocation)分析:
1. 用0 ~ 1 << N-1二进制表示物品是否装载的详细情况(即状态),其中0代表未装载,1代表装载。假设N为3,那么000表示没有装载,001表示第一件物品装载,011表示第一、二件物品装载,100表示第三件物品装载。
2. 用dp[i]表示状态i需要装载的最少次数,则此处动态规划方程为:dp[i|j] = min(dp[i|j], dp[i]+1)。其中要保证:a.i&j==0 b.j表示两趟车一次可运走的状态
3. 若(i&j == 0),表示:i状态与j状态没有重合的元素
POJ的2923(Relocation)代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define MAXVALUE 1<<30
bool isStateOK(int x, int v1, int v2, const vector<int> &vol)//判断一种状态是否可行(可以一次运走)
{
int sum = 0;
vector<bool> visit(v1+1, false); //vis[i]表示容量和为i的货物能否装上第一辆车
visit[0] = true;
for (int i = 0;i < vol.size();i++)
{