POJ1837 分组背包 xingxing在努力
题目的意思是有一个天平两臂各挂一些钩子, 每个钩子下面可以挂一些砝码, 问在使用所有的砝码的情况下有多少种方法可以使天平平衡?该问题可以转化成分组背包的问题,大体如下对于每一种砝码来说我们可以关在任意一个钩子下面,这些事件是互斥的,一个砝码一个组进行分组背包即可,注意的是有负的力矩的存在, 因此我们将坐标轴移动到10000即可,代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int C, G; int pos[25]; int weight[25]; int M = 10000; int f[25][20000]; int main() { while(scanf("%d%d", &C, &G) == 2) { for(int i=1; i<=C; i++) scanf("%d", &pos[i]); for(int i=1; i<=G; i++) scanf("%d", &weight[i]); memset(f, 0, sizeof(f)); f[0][M] = 1; for(int i=1; i<=G; i++) for(int j=0; j<=20000; j++) //有人说这个必须正向循环,其实没必要的。。也可以负向 { for(int k=1; k<=C; k++) //第i个砝码挂到第k个位置上 { int tp = weight[i]*pos[k]; if(j-tp>=0 && j-tp<=20000 && f[i-1][j-tp]) f[i][j] += f[i-1][j-tp]; } } printf("%d\n", f[G][M]); } return 0; }
使用了优化内存的方法:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int C, G; int pos[25]; int weight[25]; int M = 10000; int f[2][20000]; int main() { while(scanf("%d%d", &C, &G) == 2) { for(int i=1; i<=C; i++) scanf("%d", &pos[i]); for(int i=1; i<=G; i++) scanf("%d", &weight[i]); memset(f, 0, sizeof(f)); f[0][M] = 1; for(int i=1; i<=G; i++) { memset(f[i%2], 0, sizeof(f[i%2])); for(int j=0; j<=20000; j++) { for(int k=1; k<=C; k++) //第i个砝码挂到第k个位置上 { int tp = weight[i]*pos[k]; if(j-tp>=0 && j-tp<=20000 && f[(i-1)%2][j-tp]) f[i%2][j] += f[(i-1)%2][j-tp]; } } } printf("%d\n", f[G%2][M]); } return 0; }