Poj 1837 Balance【题解报告|dp】

题目大意:

有一个天平,天平左右两边各有若干个钩子,总共有C个钩子,有G个钩码,求将钩码全部挂到钩子上使天平平衡的方法的总数。

其中可以把天枰看做一个以x轴0点作为平衡点的横轴

这道题有点类似,都是将某个元素看作体积,另一个元素看作价值进行0-1背包,而且都需要处理正负数,建议一试。

输入:

2 4 //C 钩子数 与 G钩码数

-2 3 //负数:左边的钩子距离天平中央的距离;正数:右边的钩子距离天平中央的距离c[k]

3 4 5 8 //G个重物的质量w[i]

dp思路:

每向天平中方一个重物,天平的状态就会改变,而这个状态可以由若干前一状态获得。

首先定义一个平衡度j的概念

当平衡度j=0时,说明天枰达到平衡,j>0,说明天枰倾向右边(x轴右半轴),j<0则相反

那么此时可以把平衡度j看做为衡量当前天枰状态的一个值

因此可以定义一个 状态数组 d p [ i ] [ j ] dp[i][j] dp[i][j],意为在挂满前i个钩码时,平衡度为j的挂法的数量。(这里为什么不以位置为体积,即dp[i]意为使用完前i个位置时平衡度为j的挂法的数量,读者可以思考一下。提示:重复使用)

由于距离c[i]的范围是 − 15 − 15 -15-15 1515,钩码重量的范围是1~25,钩码数量最大是20

因此最极端的平衡度是所有物体都挂在最远端,因此平衡度最大值为 j = 15 ∗ 20 ∗ 25 = 7500 j=15*20*25=7500 j=152025=7500。原则上就应该有 d p [ 1   20 ] [ − 7500   7500 ] dp[ 1~20 ][-7500 ~ 7500 ] dp[1 20][7500 7500]

因此为了不让下标出现负数,做一个处理,使使得数组开为 d p [ 1   20 ] [ 0   15000 ] dp[1~20][0~15000] dp[1 20][0 15000],则当 j = 7500 j=7500 j=7500时天枰为平衡状态

那么每次挂上一个钩码后,对平衡状态的影响因素就是每个钩码的 力臂

力臂=重量 *臂长 = w [ i ] ∗ c [ k ] w[i]*c[k] w[i]c[k]

那么若在挂上第i个砝码之前,天枰的平衡度为j

(换言之把前i-1个钩码全部挂上天枰后,天枰的平衡度为j)

则挂上第i个钩码后,即把前i个钩码全部挂上天枰后,天枰的平衡度 j = j + w [ i ] ∗ c [ k ] j=j+ w[i]*c[k] j=j+w[i]c[k]

其中 c [ k ] c[k] c[k]为天枰上钩子的位置,代表第i个钩码挂在不同位置会产生不同的平衡度

不难想到,假设 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i1][j] 的值已知,设 d p [ i − 1 ] [ j ] = n u m dp[i-1][j]=num dp[i1][j]=num

(即已知把前i-1个钩码全部挂上天枰后得到状态j的方法有num次)

那么 d p [ i ] [ j + w [ i ] ∗ c [ k ] ] = d p [ i − 1 ] [ j ] = n u m dp[i][ j+ w[i]*c[k] ] = dp[i-1][j] = num dp[i][j+w[i]c[k]]=dp[i1][j]=num

(即以此为前提,在第k个钩子挂上第i个钩码后,得到状态 j + w [ i ] ∗ c [ k ] j+ w[i]*c[k] j+w[i]c[k]的方法也为num次)

想到这里,利用递归思想,不难得出 状态方程 d p [ i ] [ j + w [ i ] ∗ c [ k ] ] = ∑ ( d p [ i − 1 ] [ j ] ) \mathbf{dp[i][ j+ w[i]*c[k] ]= ∑(dp[i-1][j])} dp[i][j+w[i]c[k]]=dp[i1][j]

有些前辈推导方式稍微有点不同,得到的 状态方程为 d p [ i ] [ j ] = ∑ ( d p [ i − 1 ] [ j − c [ i ] ∗ w [ i ] ] ) dp[i][j] =∑(dp[i - 1][j - c[i] * w[i]]) dp[i][j]=(dp[i1][jc[i]w[i]])

其实两条方程是等价的,这个可以简单验证出来,而且若首先推导到第二条方程,也必须转化为第一条方程,这是为了避免下标出现负数

结论:

最终转化为01背包问题

状态方程 d p [ i ] [ j + w [ i ] ∗ c [ k ] ] = ∑ ( d p [ i − 1 ] [ j ] ) dp[i][ j+ w[i]*c[k] ]= ∑(dp[i-1][j]) dp[i][j+w[i]c[k]]=dp[i1][j]

初始化: d p [ 0 ] [ 7500 ] = 1 ; dp[0][7500] = 1; dp[0][7500]=1; //不挂任何重物时天枰平衡,此为一个方法

复杂度 O ( C ∗ G ∗ 15000 ) O(C*G*15000) O(CG15000) 完全可以接受

#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define inf 0x3f3f3f3f
#define MAX 15005

int dp[25][15005];//dp[i][j]:前i个重物能凑出来的值
int C, G, c[25], g[25];

int main() {
	while (scanf("%d %d", &C, &G) != EOF) {
		for (int i = 1; i <= C; i++)scanf("%d", &c[i]);
		for (int i = 1; i <= G; i++)scanf("%d", &g[i]);

		memset(dp, 0, sizeof(dp)); dp[0][7500] = 1;
		for (int i = 1; i <= G; i++) {//每一个重物
			for (int j = 1; j <= C; j++) {//每一个位置
				if (c[j] >= 0) {//右侧的位置
					for (int k = 0; k < MAX - c[j] * g[i]; k++)
						if (dp[i - 1][k])
							dp[i][k + c[j] * g[i]] += dp[i - 1][k];
				}
				else//挂在左侧某个位置
					for (int k = MAX - 1; k >= -c[j] * g[i]; k--)
						if (dp[i - 1][k])
							dp[i][k + c[j] * g[i]] += dp[i - 1][k];
			}
		}
		
		printf("%d\n", dp[G][7500]);
	}
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ3635是一道经典的数学题,需要使用一些数学知识和算法进行解决。 题目描述: 给定四个正整数 a、b、p 和 k,求 a^b^p mod k 的值。 解题思路: 首先,我们可以将指数 b^p 写成二进制形式:b^p = c0 * 2^0 + c1 * 2^1 + c2 * 2^2 + ... + ck * 2^k,其中 ci 为二进制数的第 i 位。 然后,我们可以通过快速幂算法来计算 a^(2^i) mod k 的值。具体来说,我们可以用一个变量 x 来存储 a^(2^i) mod k 的值,然后每次将 i 加 1,如果 ci 为 1,则将 x 乘上 a^(2^i) mod k,最后得到 a^b^p mod k 的值。 代码实现: 以下是 Java 的代码实现: import java.util.*; import java.math.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); BigInteger a = sc.nextBigInteger(); BigInteger b = sc.nextBigInteger(); BigInteger p = sc.nextBigInteger(); BigInteger k = sc.nextBigInteger(); BigInteger ans = BigInteger.ONE; for (int i = 0; i < p.bitLength(); i++) { if (b.testBit(i)) { ans = ans.multiply(a.modPow(BigInteger.ONE.shiftLeft(i), k)).mod(k); } } System.out.println(ans); } } 其中,bitLength() 函数用于获取二进制数的位数,testBit() 函数用于判断二进制数的第 i 位是否为 1,modPow() 函数用于计算 a^(2^i) mod k 的值,multiply() 函数用于计算两个 BigInteger 对象的乘积,mod() 函数用于计算模数。 时间复杂度: 快速幂算法的时间复杂度为 O(log b^p),其中 b^p 为指数。由于 b^p 的位数不超过 32,因此时间复杂度为 O(log 32) = O(1)。 总结: POJ3635 是一道经典的数学题,需要使用快速幂算法来求解。在实现时,需要注意 BigInteger 类的使用方法,以及快速幂算法的细节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值