Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 4100 | Accepted: 2369 |
Description
Input
Output
Sample Input
2 4 -2 3 3 4 5 8
Sample Output
2
Source
发现书看多了还是不行,要多做题!!!
DP的边界太重要了,一开开始把V_MAX值估计小了,一直WA, 仔细估算改成7500后就AC
(1)很早之前写的一个版本,用了递归,其实DP最好还是不要用递归
#include <iostream>
#define C_MAX 20
#define G_MAX 20
#define V_MAX 7500
using namespace std;
static int t1[C_MAX + 1];
static int t2[G_MAX + 1];
static int m[G_MAX + 1][C_MAX + 1];
static int v[G_MAX + 1][2 * V_MAX + 1];
int r_c = 0;
int r_v = 0;
int test(int num, int value) //DP主程序,采用备忘录
{
int tempvalue = value;
if(value < 0)
tempvalue = V_MAX - value;
if(v[num][tempvalue] != -1)
return v[num][tempvalue];
else if(num == 0 && value != 0)
{
v[num][tempvalue] = 0;
return 0;
}
else
{
int total = 0;
for(int i = 1; i <= r_c; i++)
{
total += test(num - 1, value + m[r_v - num + 1][i]); //求子问题
}
v[num][tempvalue] = total; //备忘
return total;
}
}
int main()
{
cin>>r_c>>r_v;
//
for(int i1 = 1; i1 <= r_c; i1++)
{
cin>>t1[i1];
}
for(int i2 = 1; i2 <= r_v; i2++)
{
cin>>t2[i2];
}
for(int i3 = 1; i3 <= r_v; i3++)
{
for(int i4 = 1; i4 <= r_c; i4++)
{
m[i3][i4] = t2[i3] * t1[i4];
}
}
for(int i = 0; i <= G_MAX; i++)
{
for(int j = 0; j <= 2 * V_MAX; j++)
{
v[i][j] = -1;
}
}
v[0][0] = 1;
test(r_v, 0);
cout<<v[r_v][0]<<endl; //输出
return 0;
}
(2)非递归版本
/*
典型的覆盖型背包问题,有条件可知,总的力矩的范围是-7500 ~ 7500,为了方便处理,总体迁移7500,变成1 ~15000
然后利用背包的解法依次处理所有砝码以及放置的位置
*/
#include <iostream>
#define MAX_N 15010
#define MAX_H 20
#define MAX_W 20
using namespace std;
//背包的记录数组,利用二维滚动 can[][i]表示到当前砝码可以让总力矩达到i的方案总数
int can[2][MAX_N + 1];
//输入
int hook[MAX_H + 1], weight[MAX_W + 1];
int h_n, w_n;
int main()
{
int i, j, w;
//读取输入
scanf("%d%d", &h_n, &w_n);
for(i = 0; i < h_n; i++) scanf("%d", &hook[i]);
for(i = 0; i < w_n; i++) scanf("%d", &weight[i]);
//p用来指示当前滚动数组的第一维位置
int p = 0;
memset(can, 0, sizeof(can));
//背包起始状态,处于平衡状态
can[0][7500] = 1;
//遍历砝码
for(i = 0; i < w_n; i++)
{
//遍历当前砝码可以防止的位置
for(j = 0; j < h_n; j++)
{
//当前砝码防止在当前位置可以增加的力矩值
int val = hook[j] * weight[i];
//遍历当前背包可达状态
for(w = 0; w <= MAX_N; w++)
{
if(can[p][w] != 0)
can[(p + 1) % 2][w + val] += can[p][w];
}
}
memset(can[p], 0, sizeof(can[p]));
//最后一个砝码防止完毕,输出结果,结果是平衡状态的可达途径总数
if(i == w_n - 1) printf("%d/n", can[(p + 1) % 2][7500]);
p = (p + 1) % 2;
}
return 0;
}