算法设计——天平平衡问题(Balance)(动态规划)

问题

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

题目简述:
c个位置,g个砝码,求所有砝码放上使天平平衡的方案数目

分析

当天平平衡时,天平左右的力矩相等,力矩=力臂*力

用一个二维数组dp
dp[i][j]代表放上前i个砝码后,天平左力矩与右力矩相差为j(可能为负值)的方案数量
由于这里的j是一个相对量,我们可假设所有物品都放在一边,那么相差量可能为最大也可能最小(此时负值),当最大/最小时绝对值为2015*25=7500,所以为了避免数组中出现负值,于是我们可以假设相差量为0时j=7500,即将整体加个7500的偏移量,小于7500时,j为负,大于7500时j为正。
我们得到方程dp[i][j+c[k]*g[i]]=dp[i][j+c[k]*g[i]]+dp[i-1][j],k为枚举变量

为什么是dp[i][j+c[k]*g[i]]的更新呢?因为一旦更新了dp[i][j]我们就会失去很多方案,只有更新dp[i][j+c[k]*g[i]],才更得到更加齐全的状态方案。

代码实现

#include<stdio.h>
#include<string.h>
int main()
{
	int m,n,i,j,k;
	int c[25],g[25],dp[25][15000];
	memset(dp,0,sizeof(dp));
	scanf("%d %d",&m,&n);
	dp[0][7500]=1;//有一种状态,当什么都没有的时候 
	for(i=1;i<=m;i++) scanf("%d",&c[i]);
	for(i=1;i<=n;i++) scanf("%d",&g[i]);
	for(i=1;i<=n;i++){//从第一个砝码开始 
		for(j=0;j<=15000;j++){//最小为-7500,加上7500偏移,从0开始 
			for(k=1;k<=m;k++){//枚举 
				dp[i][j+c[k]*g[i]]=dp[i][j+c[k]*g[i]]+dp[i-1][j];//状态转移 
			} 
		} 
	}
	printf("%d",dp[n][7500]);
	return 0; 
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值