POJ 1014 解题报告

这道题我用的是最原始的DFS,虽然加了cache,避免了一些重复运算,但不出意料地TLE了。然后就是“优化”。把每个value中的item个数减到200以下(看discuss可以取到30甚至6的,还有一堆mod的解法)。我都不明白这些优化的原理。见源代码中注释掉的DFS部分。

1014Accepted3736K422MSG++2013B

看到discuss中提到这道题可以用背包做。然后看了传说中的背包九讲,大致了解了,最终AC了。链接见https://github.com/tianyicui/pack。

1014Accepted916K16MSG++3727B
这道题用背包的角度看就是个多重背包问题,即有6个物品,每个物品能拿的件数是有上限的,这道题里面就是输入的数目,这道题里面第i个物品的价值是i + 1(因为我是从0~5编号的)。

然后就可以写出朴素的多重背包解法:

int goal = sum / 2;
fill(dp.begin(), dp.begin() + goal + 1, INT_MIN);
dp[0] = 0;
for (int i = 0; i < 6; ++i)
{
    for (int w = 1; w <= nums[i]; ++w)
    {
        for (int v = goal; v >= (i + 1) * w; --v)
        {
            dp[v] = max(dp[v], dp[v - (i + 1) * w] + (i + 1) * w);
        }
    }
}
if (dp[goal] == goal)
{
    cout << "Collection #" << seq << ":" << endl;
    cout << "Can be divided." << endl;
    cout << endl;
}
else
{
    cout << "Collection #" << seq << ":" << endl;
    cout << "Can't be divided." << endl;
    cout << endl;
}
这道题实质是看价值goal能不能通过在6个物品中各拿一定件数获得,所以最终判断dp[goal]==goal.中间的状态转移也是对每件物品的每个件数,看拿之前的那个价值能不能到达这个价值。初始化可以都初始成0,这样表示所有价值中只有0到了(没有拿任何item)。也可以把别的都初始化成INT_MIN。应该不影响。

这样做最后会TLE,因为每个物品的件数可能很多,循环的常数太大。一个优化是背包九讲中提到的。把物品能取的上限W分成多个“物品”,每个物品的系数分别是1, 2, 4, ..., 2^(k - 1), W - 2^k - 1。其中k是使得W - 2^k - 1>0的最大k。比如13只用试1, 2, 4, 6。虽然转化成了0~1背包,但是原来同一个物品产生出来的这些“物品”都是在前一个“物品”的基础上更新DP的,所以他们之间实质是叠加关系。而这样取系数的方式保证了所有1~W之间的所有数都是能取到的。具体分析见背包九讲。这个优化力度是非常大的。直接就从TLE到了16MS。

			for (int i = 0; i < 6; ++i)
			{
				// for (int w = 1; w <= nums[i]; ++w)
				// {
				// 	for (int v = goal; v >= (i + 1) * w; --v)
				// 	{
				// 		dp[v] = max(dp[v], dp[v - (i + 1) * w] + (i + 1) * w);
				// 	}
				// }

				int W = nums[i];
				for (int k = 1; k < W; k <<= 1)
				{
					for (int v = goal; v >= (i + 1) * k; --v)
					{
						dp[v] = max(dp[v], dp[v - (i + 1) * k] + (i + 1) * k);
					}
					W -= k;
				}

				for (int v = goal; v >= (i + 1) * W; --v)
				{
					dp[v] = max(dp[v], dp[v - (i + 1) * W] + (i + 1) * W);
				}

			}


/* 
ID: thestor1 
LANG: C++ 
TASK: poj1014 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>


using namespace std;


// std::vector<std::vector<bool> > cache(60000, std::vector<bool>(6, false));


// bool DFS(int index, int total, const int goal, int nums[])
// {
// <span style="white-space:pre">	</span>if (total == goal)
// <span style="white-space:pre">	</span>{
// <span style="white-space:pre">		</span>return true;
// <span style="white-space:pre">	</span>}


// <span style="white-space:pre">	</span>assert (total < goal);


// <span style="white-space:pre">	</span>if (index < 0)
// <span style="white-space:pre">	</span>{
// <span style="white-space:pre">		</span>return false;
// <span style="white-space:pre">	</span>}


// <span style="white-space:pre">	</span>if (cache[total][index])
// <span style="white-space:pre">	</span>{
// <span style="white-space:pre">		</span>return false;
// <span style="white-space:pre">	</span>}


// <span style="white-space:pre">	</span>cache[total][index] = true;


// <span style="white-space:pre">	</span>for (int i = 0; i <= nums[index]; ++i)
// <span style="white-space:pre">	</span>{
// <span style="white-space:pre">		</span>if (total + i * (index + 1) <= goal)
// <span style="white-space:pre">		</span>{
// <span style="white-space:pre">			</span>if (DFS(index - 1, total + i * (index + 1), goal, nums))
// <span style="white-space:pre">			</span>{
// <span style="white-space:pre">				</span>return true;
// <span style="white-space:pre">			</span>}
// <span style="white-space:pre">		</span>}
// <span style="white-space:pre">	</span>}


// <span style="white-space:pre">	</span>return false;
// }


// int main1()
// {
// <span style="white-space:pre">	</span>int nums[6];
// <span style="white-space:pre">	</span>int seq = 1;
// <span style="white-space:pre">	</span>while (true)
// <span style="white-space:pre">	</span>{
// <span style="white-space:pre">		</span>for (int i = 0; i < 6; ++i)
// <span style="white-space:pre">		</span>{
// <span style="white-space:pre">			</span>cin >> nums[i];
// <span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>
// <span style="white-space:pre">		</span>int sum = 0;
// <span style="white-space:pre">		</span>for (int i = 0; i < 6; ++i)
// <span style="white-space:pre">		</span>{
// <span style="white-space:pre">			</span>// optimize
// <span style="white-space:pre">			</span>// I don't know why
// <span style="white-space:pre">			</span>while (nums[i] > 200)
// <span style="white-space:pre">			</span>{
// <span style="white-space:pre">				</span>nums[i] -= 2;
// <span style="white-space:pre">			</span>}
// <span style="white-space:pre">			</span>sum += nums[i] * (i + 1);
// <span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>
// <span style="white-space:pre">		</span>if (sum == 0)
// <span style="white-space:pre">		</span>{
// <span style="white-space:pre">			</span>break;
// <span style="white-space:pre">		</span>}


// <span style="white-space:pre">		</span>if (sum & 1)
// <span style="white-space:pre">		</span>{
// <span style="white-space:pre">			</span>cout << "Collection #" << seq << ":" << endl;
// <span style="white-space:pre">			</span>cout << "Can't be divided." << endl;
// <span style="white-space:pre">			</span>cout << endl;
// <span style="white-space:pre">		</span>}
// <span style="white-space:pre">		</span>else
// <span style="white-space:pre">		</span>{
// <span style="white-space:pre">			</span>int goal = sum / 2;
<span style="white-space:pre">			</span>
// <span style="white-space:pre">			</span>for (int i = 0; i < goal; ++i)
// <span style="white-space:pre">			</span>{
// <span style="white-space:pre">				</span>for (int j = 0; j < 6; ++j)
// <span style="white-space:pre">				</span>{
// <span style="white-space:pre">					</span>cache[i][j] = false;
// <span style="white-space:pre">				</span>}
// <span style="white-space:pre">			</span>}


// <span style="white-space:pre">			</span>int index = 5;
// <span style="white-space:pre">			</span>while (nums[index] == 0)
// <span style="white-space:pre">			</span>{
// <span style="white-space:pre">				</span>index--;
// <span style="white-space:pre">			</span>}
// <span style="white-space:pre">			</span>assert(index >= 0);


// <span style="white-space:pre">			</span>int total = index + 1;
// <span style="white-space:pre">			</span>nums[index]--;
// <span style="white-space:pre">			</span>if (DFS(index, total, goal, nums))
// <span style="white-space:pre">			</span>{
// <span style="white-space:pre">				</span>cout << "Collection #" << seq << ":" << endl;
// <span style="white-space:pre">				</span>cout << "Can be divided." << endl;
// <span style="white-space:pre">				</span>cout << endl;
// <span style="white-space:pre">			</span>}
// <span style="white-space:pre">			</span>else
// <span style="white-space:pre">			</span>{
// <span style="white-space:pre">				</span>cout << "Collection #" << seq << ":" << endl;
// <span style="white-space:pre">				</span>cout << "Can't be divided." << endl;
// <span style="white-space:pre">				</span>cout << endl;
// <span style="white-space:pre">			</span>}
// <span style="white-space:pre">		</span>}
// <span style="white-space:pre">		</span>seq++;
// <span style="white-space:pre">	</span>}
// <span style="white-space:pre">	</span>return 0;  
// }


std::vector<int> dp(60001, 0);


int main()
{
<span style="white-space:pre">	</span>int nums[6];
<span style="white-space:pre">	</span>int seq = 1;
<span style="white-space:pre">	</span>while (true)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>int sum = 0;
<span style="white-space:pre">		</span>for (int i = 0; i < 6; ++i)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>cin >> nums[i];
<span style="white-space:pre">			</span>sum += nums[i] * (i + 1);
<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>if (sum == 0)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>break;
<span style="white-space:pre">		</span>}


<span style="white-space:pre">		</span>if (sum & 1)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>cout << "Collection #" << seq << ":" << endl;
<span style="white-space:pre">			</span>cout << "Can't be divided." << endl;
<span style="white-space:pre">			</span>cout << endl;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>else
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>int goal = sum / 2;
<span style="white-space:pre">			</span>fill(dp.begin(), dp.begin() + goal + 1, INT_MIN);
<span style="white-space:pre">			</span>dp[0] = 0;
<span style="white-space:pre">			</span>for (int i = 0; i < 6; ++i)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>// for (int w = 1; w <= nums[i]; ++w)
<span style="white-space:pre">				</span>// {
<span style="white-space:pre">				</span>// <span style="white-space:pre">	</span>for (int v = goal; v >= (i + 1) * w; --v)
<span style="white-space:pre">				</span>// <span style="white-space:pre">	</span>{
<span style="white-space:pre">				</span>// <span style="white-space:pre">		</span>dp[v] = max(dp[v], dp[v - (i + 1) * w] + (i + 1) * w);
<span style="white-space:pre">				</span>// <span style="white-space:pre">	</span>}
<span style="white-space:pre">				</span>// }


<span style="white-space:pre">				</span>int W = nums[i];
<span style="white-space:pre">				</span>for (int k = 1; k < W; k <<= 1)
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>for (int v = goal; v >= (i + 1) * k; --v)
<span style="white-space:pre">					</span>{
<span style="white-space:pre">						</span>dp[v] = max(dp[v], dp[v - (i + 1) * k] + (i + 1) * k);
<span style="white-space:pre">					</span>}
<span style="white-space:pre">					</span>W -= k;
<span style="white-space:pre">				</span>}


<span style="white-space:pre">				</span>for (int v = goal; v >= (i + 1) * W; --v)
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>dp[v] = max(dp[v], dp[v - (i + 1) * W] + (i + 1) * W);
<span style="white-space:pre">				</span>}


<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>if (dp[goal] == goal)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>cout << "Collection #" << seq << ":" << endl;
<span style="white-space:pre">				</span>cout << "Can be divided." << endl;
<span style="white-space:pre">				</span>cout << endl;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>else
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>cout << "Collection #" << seq << ":" << endl;
<span style="white-space:pre">				</span>cout << "Can't be divided." << endl;
<span style="white-space:pre">				</span>cout << endl;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>seq++;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值