Balance
Description
Gigel has a strange "balance" and he wants to poise it. Actually, the device is different from any other ordinary balance.
It orders two arms of negligible weight and each arm's length is 15. Some hooks are attached to these arms and Gigel wants to hang up some weights from his collection of G weights (1 <= G <= 20) knowing that these weights have distinct values in the range 1..25. Gigel may droop any weight of any hook but he is forced to use all the weights. Finally, Gigel managed to balance the device using the experience he gained at the National Olympiad in Informatics. Now he would like to know in how many ways the device can be balanced. Knowing the repartition of the hooks and the set of the weights write a program that calculates the number of possibilities to balance the device. It is guaranteed that will exist at least one solution for each test case at the evaluation. Input
The input has the following structure:
• the first line contains the number C (2 <= C <= 20) and the number G (2 <= G <= 20); • the next line contains C integer numbers (these numbers are also distinct and sorted in ascending order) in the range -15..15 representing the repartition of the hooks; each number represents the position relative to the center of the balance on the X axis (when no weights are attached the device is balanced and lined up to the X axis; the absolute value of the distances represents the distance between the hook and the balance center and the sign of the numbers determines the arm of the balance to which the hook is attached: '-' for the left arm and '+' for the right arm); • on the next line there are G natural, distinct and sorted in ascending order numbers in the range 1..25 representing the weights' values. Output
The output contains the number M representing the number of possibilities to poise the balance.
Sample Input 2 4 -2 3 3 4 5 8 Sample Output 2 Source |
=====================================题目大意=====================================
Gigel有一个两臂重量可以忽略不计的天平,天平的的两臂上有一些挂钩,Gigel 还有一些重物,任何一个重物都可以挂在任何一
个挂钩上。
求解把所有的重物都挂在天平的挂钩上使得天平处于平衡状态的方案数。
=====================================算法分析=====================================
首先对天平定义一个平衡程度d=∑(Weights[i]×Hook[Loc[i]])(其中Loc[i]是第i个重物所在的挂钩)。
d的意义就是:d<0时天平左倾,d=0时天平平衡,d>0时天平右倾。
接下来就可以定义状态F[i][j]来表示用前i种重物使得天平平衡程度为j的方案数,所求即为F[G][0]。
状态转移方程也不难得到:F[i][j]=∑F[i-1][j-Weights[i]×Hook[k]]。
不过因为j的最小值是负值(假设其取值范围为[mind,maxd]),所以用数组存储时就要偏移处理j使该区间映射为[0,maxd-mind],那
么最终答案变为F[G][-mind]。
另外方程F[i][j]=∑F[i-1][j-Weights[i]×Hook[k]]是对F[i][j]累加其所有可能的前一状态F[i-1][j-Weights[i]×Hook[k]]。
我写的时候其实是用F[i-1][j]去更新它所有可能的后一状态F[i][j+Weights[i]×Hook[k]]。
这样写的好处是可以优化一点时间,因为对于F[i-1][j]=0(方案数为0表示不可能出现)这种状态可以忽略,不过优化作用不是很明显。
还有就是我写的时候用滚动数组优化了空间。
最后其实可以发现本题是一个分组背包:
G组物品(G个重物),每组物品C个(C个挂钩),从每组物品中选且只选一个(一个重物挂在一个挂钩上),装入容量为0的背包中。
=======================================代码=======================================
#include<stdio.h>
#include<string.h>
int C,G,Weights[25],Hook[25],F[2][15005];
int main()
{
while(scanf("%d%d",&C,&G)==2)
{
for(int i=1;i<=C;++i)
{
scanf("%d",&Hook[i]);
}
int minbaldeg=0; //minimum balance degree (abs)
int maxbaldeg=0; //maximum balance degree (abs)
for(int i=1;i<=G;++i)
{
scanf("%d",&Weights[i]);
minbaldeg-=Weights[i]*Hook[1];
maxbaldeg+=Weights[i]*Hook[C];
}
int cur=0; //指向滚动数组的当前维度
memset(F[cur],0,sizeof(F[cur]));
F[cur][minbaldeg]=1; //天平不挂重物自平衡算一种方案
for(int i=1;i<=G;++i)
{
cur=!cur;
memset(F[cur],0,sizeof(F[cur]));
for(int j=0;j<=minbaldeg+maxbaldeg;++j) if(F[!cur][j]) //忽略F[!cur][j]=0的状态
{
for(int k=1;k<=C;++k) if(j+Weights[i]*Hook[k]>=0)
{
F[cur][j+(Weights[i]*Hook[k])]+=F[!cur][j];
}
}
}
printf("%d\n",F[cur][minbaldeg]);
}
return 0;
}