分弹珠(动态规划+多重背包)- HDU 1059
Posted ACM算法日常
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分弹珠(动态规划+多重背包)- HDU 1059相关的知识,希望对你有一定的参考价值。
动态规划中比较经典一类问题是背包问题,而背包问题又会产生很多的变种,容易混淆的是,说起背包,有些人可能会想到贪心算法,其实贪心算法只能解决部分满足拟阵性质的背包问题,具体后面再提贪心算法。
背包问题主要分为0-1背包,完全背包和多重背包,简单的说,0-1背包是指物品只有一个,用了就没了,而完全背包是物品不设置上限,多重背包是指物品数量设置上限的。
本题就是多重背包,每个类型的弹珠有一定的数量。
背包问题都有固定的状态转移方程,这篇暂时不做解释,详细可以看网上比较系统的解释。推荐经典的《背包九讲》:
https://github.com/tianyicui/pack/blob/master/V2.pdf
Problem Description
Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the collection in half. But unfortunately, some of the marbles are larger, or more beautiful than others. So, Marsha and Bill start by assigning a value, a natural number between one and six, to each marble. Now they want to divide the marbles so that each of them gets the same total value.
Unfortunately, they realize that it might be impossible to divide the marbles in this way (even if the total value of all marbles is even). For example, if there are one marble of value 1, one of value 3 and two of value 4, then they cannot be split into sets of equal value. So, they ask you to write a program that checks whether there is a fair partition of the marbles.
玛莎和比尔有一堆弹珠,他们想把弹珠分开,一人一份。如果弹珠的大小一样就好了,那样直接一人一半。不幸的是,这些弹珠大小不一。所以他们俩就给每个弹珠编了一个号,从1到6,现在他们想把这些弹珠分成两份,只要他们最后得到的总值一样就可以。然而问题又来了,因为他们发现如果弹珠是1、3、4、4这种情况,他们任然无法平分。所以现在他们想让你确定一下他们这堆弹珠是否能够被平分。
Input
Each line in the input describes one collection of marbles to be divided. The lines consist of six non-negative integers n1, n2, ..., n6, where ni is the number of marbles of value i. So, the example from above would be described by the input-line ``1 0 1 2 0 0''. The maximum total number of marbles will be 20000.
每行是一个弹珠集合,因为弹珠只有6种,故只有6个数字,依次代表编号n的数量。
The last line of the input file will be ``0 0 0 0 0 0''; do not process this line.
输入6个0结束。
Output
For each colletcion, output ``Collection #k:'', where k is the number of the test case, and then either ``Can be divided.'' or ``Can't be divided.''.
如果能够被平分:输出Can be divided.
否则输出:Can't be divided.
Output a blank line after each test case.
Sample Input
1 0 1 2 0 0
1 0 0 0 1 1
0 0 0 0 0 0
Sample Output
Collection #1:
Can't be divided.
Collection #2:
Can be divided.
解题说明:
1、一开始将弹珠数量分成两半,判断弹珠是否能够恰好相加得到这个值。
2、采用了动态规划的算法,优先深度搜索,当深度搜索无法继续的时候,开始回溯。
3、深度优先搜索其实很快就能够走到最后几步,回溯的时候深度比较少,因此递归算法的效率还可以,毕竟没有用到额外内存。
4、dfs函数理解起来比较难,虽然只有几行代码,建议先回头看背包和动态规划加深印象再琢磨代码。
源代码:G++ 15ms
#include <stdio.h>
int marble_count[7];
//0 5 6 1 6 5
int dfs(int val, int num)
{
//如果回溯到0了,无法继续,则失败
if (num <= 0)
return 0;
//深度搜索中刚好匹配完成
if (val == 0)
return 1;
//寻找可以用来减的值
while (num > 0 && (marble_count[num] == 0 || val < num))
num--;
//减去这个位置值
marble_count[num]--;
//优先深度搜索,如果搜索失败,尝试回溯
return (dfs(val - num, num) || dfs(val, num - 1));
}
int main()
{
int number = 0;
while (++number)
{
int sum = 0;
//将总和加起来
for (int i = 1; i <= 6; i++)
{
scanf("%d", &marble_count[i]);
sum += marble_count[i] * i;
}
//如果和为0,表示输入了6个0
if (sum == 0)
break;
printf("Collection #%d:\n", number);
//如果和为奇数,肯定不能平分
if (sum % 2)
{
printf("Can't be divided.\n\n");
continue;
}
//一人一半
sum /= 2;
if (dfs(sum, 6))
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}
以上是关于分弹珠(动态规划+多重背包)- HDU 1059的主要内容,如果未能解决你的问题,请参考以下文章