Poj 1837 Balance (DP_背包)

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


题目大意:天平平衡问题,给定m个可以放置砝码的位置,左边为负数,右边为正数,然后给定n个砝码,重量从1..25不等,位置和重量都不会出现相同的值。最后问让天平平衡的放置方法数。


解题思路:将砝码的重量乘以各个位置得到一个n*m的矩阵,表示第i个砝码在第j个位置的权值,算出权值后每一行算一组,因为只可能防放置在一个地方,那这样问题就转换为求最后的权值和为0的方案数的分组背包。转换之后,还要考虑一个问题,权值为负数的时候怎么处理,自己写个hash函数,把负数映射到正权值之和没办法到达的地方。在写的时候为了增加效率,把正权值和和负权值和给算了出来,然后作为容量的上下界,没想到这个竟然有错,无奈把上下界改成8000和-8000就过了,因为正权值最大为20 * 25 * 15 = 7500,各大一点保险。

    状态转移方程: dp[i][Gethash(j)] += dp[i-1][Gethash(j-val[i][k])]; (1 <= i <= n, 1 <= k <= m,GetHash函数为映射函数),复杂度O(16000*N*M).  


测试数据:

2 5
-2 3 
3 4 5 8 1

3 3
-1 0 1
1 2 3


代码:

#include <stdio.h>
#include <string.h>
#define MIN 50
#define MAX 10000 


int n,m,dp[MIN][MAX*2];
int val[MIN][MIN],pos[MIN];


int GetHash(int x) {

	if (x < 0) return MAX - x;
	else return x;
}
int Solve_1A() {

	int i,j,k;


	for (k = 1; k <= m; ++k)
		dp[1][GetHash(val[1][k])] = 1;
	for (i = 2; i <= n; ++i)
		for (j = 8000; j >= -8000; --j)
			for (k = 1; k <= m; ++k)
				dp[i][GetHash(j)] += dp[i-1][GetHash(j-val[i][k])];
	return dp[n][0];
}


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


	while (scanf("%d%d",&m,&n) != EOF) {
	//n 表示有几种weight,m表示几个位置
		memset(dp,0,sizeof(dp));
		for (i = 1; i <= m; ++i)
			scanf("%d",&pos[i]);
		for (i = 1; i <= n; ++i) {

			scanf("%d",&k);
			for (j = 1; j <= m; ++j) 
				val[i][j] = k * pos[j];
		}


		int ans = Solve_1A();
		printf("%d\n",ans);
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

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