PC/UVa:111106/10261
汽车通过海峡时需要装载到船上,然后由船运抵对岸。每条船有两条相同长度的车道,单位为米,每辆车的长度不同,单位为厘米。给定一个等待上船的汽车队列,求最多可以装载多少辆车,以及装载方法。
这道题依然是线性结构的动态规划,但是有几个特别的地方:
- 不需要排序
- 轮到这辆车时,必须装载它,不能丢弃
我感觉这道题也可以不叫动态规划,就是一个使用递推代替穷举的题目。
在已经装载i
辆车时,根据车的顺序,可以得到左右两车道的各种排列方式,以及每种排列方式中有多少辆车和总长度。当装载第i + 1
辆车时,可以停在左车道,也可以停在右车道,或者两个车道都已经没有位置了(这时就得到了解为i
辆车)。如果可以停在左车道,那么左车道的车辆数加1
,总长度增加当前车的长度;如果可以停在右车道,那么左车道的车辆数目不变,总长度也不变。这道题也不需要合并重叠子问题,因为不能丢弃任意一辆车,所以没有什么状态是相同的。根据此递推关系,可以记录装载i
辆车时,左车道的车辆长度(当然记录左车道装载了哪些车也可以,但是在装载下一辆车时需要通过计算来确定车道长度)。
装载每一辆车之前,枚举左车道所有可能的车道长度,同时判断右车道长度是否也是合理的:
- 如果可以停到左车道,左车道长度更新,同时记录这辆车可以装载
- 如果可以停到右车道,左车道长度不变(因此需要每次判断右车道长度是否满足要求),同时记录这辆车可以装载
- 如果在左车道已有各种长度下,左右车道都没有空间了,则停止装载
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
void printChoice(const vector<vector<vector<bool>>> &Length,
const vector<size_t> &vecCarLen,
const size_t curr, const int leftLen)
{
if (curr != 1){
if (Length[curr][leftLen][1]){
printChoice(Length, vecCarLen, curr - 1, leftLen - vecCarLen[curr - 1]);
}
else{
printChoice(Length, vecCarLen, curr - 1, leftLen);
}
}
if (Length[curr][leftLen][1]){
cout << "port" << endl;
}
else cout << "starboard" << endl;
}
void loadCar(const vector<size_t> &vecCarLen, const size_t cm)
{
vector<size_t> vecTotalLen;
if (!vecCarLen.empty()) vecTotalLen.push_back(vecCarLen[0]);
for (size_t idx = 1; idx < vecCarLen.size(); idx++)
{
vecTotalLen.push_back(vecTotalLen.back() + vecCarLen[idx]);
}
vector<vector<vector<bool>>> Length(vecCarLen.size() + 1, vector<vector<bool>>(cm + 1, vector<bool>(2, false)));
Length[0][0][0] = true;
Length[0][0][1] = true;
size_t curr = 1;
bool bCurr = false;
for (; curr <= vecCarLen.size(); curr++)
{
bCurr = false;
size_t currLen = vecCarLen[curr - 1];
size_t currTotalLen = vecTotalLen[curr - 1];
Length[curr] = Length[curr - 1];
for (size_t len = 0; len < cm + 1; len++)
{
size_t lastRightLen = currTotalLen - currLen - len;
if (Length[curr - 1][len][0] && lastRightLen <= cm){
size_t newLen = len + currLen;
if (newLen <= cm){//放左边
Length[curr][newLen][0] = true;
Length[curr][newLen][1] = true;
bCurr = true;
}
if (currTotalLen - len <= cm){//放右边
Length[curr][len][0] = true;
Length[curr][len][1] = false;
bCurr = true;
}
}
}
if (!bCurr) break;
}
if (curr > vecCarLen.size() || !bCurr){
curr--;
}
cout << curr << endl;
if (curr != 0){
int leftLen = cm;
while (leftLen > 0){
if (Length[curr][leftLen][0]) break;
leftLen--;
}
printChoice(Length, vecCarLen, curr, leftLen);
}
}
int main()
{
int T = 0;
cin >> T;
for (int t = 0; t < T; t++)
{
size_t meter;
cin >> meter;
cin.get();
meter *= 100;
vector<size_t> vecCarLen;
string strLine;
while (cin >> strLine){
int CarLen;
istringstream iss(strLine);
iss >> CarLen;
if (CarLen == 0) break;
vecCarLen.push_back(CarLen);
}
loadCar(vecCarLen, meter);
if (t != T - 1) cout << endl;
}
return 0;
}
/*
1
50
2500
3000
1000
1000
1500
700
800
0
*/