POJ1837--二维背包

Balance
Time Limit: 1000MS
Memory Limit: 30000K
Total Submissions: 13525
Accepted: 8474

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

题目大意:给定一个天平,然后给定位置和一定数量的砝码,问有多少种方法能够使得天平达到平衡(注意:给定的砝码每一种只有一个,但是需要全部用完

样例:2 4//第一个数代表有两个地方可以挂载砝码,4代表有4个砝码

-2 3//两个挂载位置,-2代表在天平左侧距离天平中心长度为2的地方,3代表在天平右侧距离天平中心长度为3的地方

3 4 5 8//分别代表4个砝码的质量


解题思路:

PS:参考了大神的思路(●'◡'●)

首先找出两个维度,第一维度为第几个砝码"i",第二个维度是天平的平衡度"j"。其中平衡度<0代表向左侧倾斜,平衡度>0代表向右侧倾斜,==0代表符合题目叙述要求。假设全部砝码挂在一端的外侧,那么最大的平衡度=15(天平臂长)*20(砝码数量)*25(最重的砝码数量)=7500。左侧为-7500,右侧为7500。避免负数带来的麻烦,整体偏移7500,得到0-15000,其中7500就是代表的原来的平衡位置。

再考虑状态转移方程,用dp[i][j]代表当挂第i个砝码时,平衡度能够达到j所产生的方法的数目。同时力矩=臂长*重量。

所以当dp[i][j]确定的时候,他能够向后影响dp[i+1][j+c[k]*w[i+1]]

注意:这里的k小标代表的是输入数据中的挂载位置,因为位置的不同,所以实际上dp[i][j]产生了k个影响。

那么站在任意一个dp[i+1][j+c[k]*w[i+1]]的情况来说,dp[i][j]为它产生了多少种新的方法呢?当然是dp[i][j]种,

即在原有的基础上增加了dp[i][j]种,就有dp[i+1][j+c[k]*w[i+1]]+=dp[i][j];

如果是dp[i-1][j]对dp[i][j+c[k]*w[i]]呢?同理,得到dp[i][j+w[i]*c[k]]+=dp[i-1][j];

所以,状态转移方程就是dp[i][j+w[i]*c[k]]+=dp[i-1][j]当然也可以刚开始推到的那一种,为了使用方便起见,用这一个,其实一样。

记得仔细想一想无向后性...


源代码:

<span style="font-size:24px;">#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
using namespace std;

int dp[21][15001];
int main() {
	int i, j, k;//控制变量的下标
	int n, g;
	int c[21], w[21];
	memset(dp,0,sizeof(dp));
	dp[0][7500] = 1;//不放砝码时平衡度为7500至少有一种方法,初始化 
	scanf("%d%d",&n,&g);//位置个数,砝码的个数 
	for(i = 1; i <= n; i++) {
		scanf("%d",&c[i]);
	}
	for(j = 1; j <= g; j++) {
		scanf("%d",&w[j]);
	}
	for(i = 1; i <= g; i++) {
		for(j = 0; j <= 7500*2; j++) {
			//因为砝码所处位置的不同,所以需要再写for循环加和,才能够得到对应
			//受到影响的dp[i][j+w[i]*c[k]],一个dp[i-1][j]产生n个影响 
			for(k = 1; k <= n; k++) {
				dp[i][j+w[i]*c[k]]+=dp[i-1][j];
			}
		}
	}
	printf("%d
",dp[g][7500]);//最后结果保存在dp[g][7500]中
	return 0;
} </span>


原文地址:https://www.cnblogs.com/lemonbiscuit/p/7776119.html