原题链接:P2946 [USACO09MAR] Cow Frisbee Team S
这个题目一眼01背包 首先考虑背包的两个维度和所对应的含义值
dp[i][j]
i:所选中的奶牛
j:所占用的能力值
dp[i][j]:在之前所有所选的奶牛中符合所占用的能力值的可选方案数
定义好背包后我们去寻找状态转移方程
由题意可得我们当前点可以选可以不选
不选: dp[i][j] = dp[i-1][j];
选:dp[i][j] = dp[i][j]+dp[i-1][j-w[i]] (注意 dp[i][j]要初始化一遍)
所以我们的状态转移方程:dp[i][j] = dp[i-1][j]+dp[i][j]+dp[i-1][j-w[i]];
但是我们考虑到这个题目有个问题就是 背包可能是需要F的倍数
这个问题如何解决??
如果我们选择开一个数组为N=2000,M=1e5 那肯定会爆
所以我们考虑到取余这个方法
直接上代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2010, MOD = 1e8;
int w[N];
int n, m;
int dp[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> w[i];
w[i] %= m;
}
for (int i = 1; i <= n; i++) {
dp[i][w[i]] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) {//注意余数,比方说m是5对应的值就是0的位置
dp[i][j] = ((dp[i - 1][j] +dp[i][j])%MOD+ dp[i - 1][j - w[i]])%MOD;//每一次运算都mod
}
}
cout << dp[n][0];
}
很好,完美错误 这里出了一个问题 也就是dp[i-1][j-w[i]]的位置不对
我们需要让他加上m再modm就对了
正解:
#include<bits/stdc++.h>
using namespace std;
const int N = 2010, MOD = 1e8;
int w[N];
int n, m;
int dp[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> w[i];
w[i] %= m;
}
for (int i = 1; i <= n; i++) {
dp[i][w[i]] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) {
dp[i][j] = ((dp[i - 1][j] +dp[i][j])%MOD+ dp[i - 1][(j - w[i]+m)%m])%MOD;
}
}
cout << dp[n][0];
}