poj 1837 Balance (DP__记忆化搜索)

题目链接http://poj.org/problem?id=1837


题目大意:给定一个天平,有C个地方可以挂砝码,这C个地方有坐标,负数代表在左边,正数代表在右边。有G个砝码,砝码有权重,每个砝码都必须挂且只能挂在一个钩子上。问最后如何组合才能使天平平衡。


解题思路:状态转移方程:dp[i][k+arr[i][j]] += dp[i][k]; {1 <= i <=G,0 <= k <= 4000*2 ,1<=j<=C}


 可以将每个位置的坐标与砝码权重相乘得到一个矩阵。因为每个砝码都必须挂,现在问题就转化为在G*C的矩阵中每行找1个数arr[i][j]使得最后相加和为0。因为每个砝码都必须挂,最后一个砝码放在什么位置能使总和为0由前一个砝码决定,以此类推,得到一个转移方程

 其实转移方程很好想,复杂的是矩阵出现负数,所以利用hash求解,欲知详情如何,请看代码。


测试数据:

2 4
-2 3 
3 4 5 8
3 3
-1 -2 3
1 2 3
20 20
-15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25


代码:

#include <stdio.h>
#include <string.h>
#include <map>
using namespace std;
#define MAX 4000


int n,m,low,high; 
int arr[30],brr[30];
int val[30][30];
int dp[30][MAX*2];


int main()
{
	int i,j,k,maxx;


	while (scanf("%d%d",&n,&m) != EOF) {

		for (i = 1; i <= n; ++i)
			scanf("%d",&arr[i]);
		for (j = 1; j <= m; ++j)
			scanf("%d",&brr[j]);


		for (i = 1; i <= m; ++i)
			for (j = 1; j <= n; ++j) {

				val[i][j] = arr[j] * brr[i];
				if (val[i][j] >= 0 && i == 1) dp[1][val[i][j]] = 1;
				else if (i == 1 && val[i][j] < 0) dp[1][MAX-val[i][j]] = 1;
			}


		for (i = 2; i <= m; ++i)	//列
			for (j = 1; j <= n; ++j) { //行 
			
				for (k = 0; k < MAX; ++k)
					if (val[i][j] + k >= 0 && val[i][j] + k < MAX)
						dp[i][k + val[i][j]] += dp[i-1][k];
					else if (val[i][j] + k < 0)
						dp[i][MAX-val[i][j]-k] += dp[i-1][k];
					
				
				for (k = MAX; k < 2 * MAX; ++k) {
				
					int tp = MAX - k;
					if (val[i][j] + tp >= 0) dp[i][val[i][j] + tp] += dp[i-1][k];
					else if (val[i][j] + tp < 0) dp[i][MAX-val[i][j]-tp] += dp[i-1][k];
				}

			}
		printf("%d\n",dp[m][0]);
	}
}

你可能感兴趣的:(c,测试)