题目
一般DP代码(注意,这里只能向外推(起始状态是f(1,0),不能向内推(不然会导致之前的羊圈被割裂))
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 210;
const int MAX_M = 16;
int n, m;
double p[MAX_N];
int l[MAX_M];
double dp[MAX_N][1 << MAX_M];
int main() {
cin >> m >> n;
for (int i = 1; i <= m; i++) cin >> l[i];
for (int i = 1; i <= n; i++) cin >> p[i];
int mask = 1 << m;
for (int i = 0; i <= n + 1; i++) {
for (int j = 0; j < mask; j++) {
dp[i][j] = 1e18;
}
}
dp[1][0] = 0;
for (int u = 1; u <= n; u++) {
for (int s = 0; s < mask; s++) {
if (dp[u][s] == 1e18) continue;
// 不覆盖当前羊u
if (u + 1 <= n + 1) {
dp[u + 1][s] = min(dp[u + 1][s], dp[u][s] + p[u]);
}
// 尝试用未使用的羊圈i覆盖
for (int i = 1; i <= m; i++) {
if (!(s & (1 << (i - 1))) && u + l[i] - 1 <= n) {
int new_s = s | (1 << (i - 1));
dp[u + l[i]][new_s] = min(dp[u + l[i]][new_s], dp[u][s]);
}
}
}
}
double ans = 1e18;
for (int s = 0; s < mask; s++) {
ans = min(ans, dp[n + 1][s]);
}
printf("%.2lf\n", ans);
return 0;
}
记忆化搜索DP代码
cpp
#include <bits/stdc++.h>
using namespace std;
using db = double;
int n, m;
db p[210];
int w[20];
db dp[210][(1 << 15) + 10];
db f(int u, int s)
{
if(u >= n+1) return 0;
if(dp[u][s] != -1) return dp[u][s];
db ret = 1e18;
//不用,状态不变,但是值要增加(这里的值指的是逃跑期望)
ret = p[u] + f(u+1, s);
//用
for(int i = 1; i <= m; i++)
{
if(!(s & (1 << (i-1))) && u + w[i] - 1 <= n)
{
ret = min(ret, f(u+w[i], s | (1 << (i-1))));
}
}
return dp[u][s] = ret;
}
int main()
{
cin >> m >> n;
for(int i = 1; i <= m; i++)
cin >> w[i];
for(int i = 1; i <= n; i++)
cin >> p[i];
for(int i = 1; i <= n; i++)
for(int j = 0; j < 1 << m; j++)
dp[i][j] = -1;
printf("%.2lf", f(1, 0));
}
感想

另外勘误
这题很多解法都是没看到"最多"吗

为什么要加这个限制?

cpp
#include <bits/stdc++.h>
using namespace std;
using db = double;
int n, m;
db p[210];
int w[20];
db dp[210][(1 << 15) + 10];
db f(int u, int s)
{
if(u >= n+1) return 0;
if(dp[u][s] != -1) return dp[u][s];
db ret = 1e18;
//不用,状态不变,但是值要增加(这里的值指的是逃跑期望)
ret = p[u] + f(u+1, s);
//用
for(int i = 1; i <= m; i++)
{
if(!(s & (1 << (i-1))))
{
ret = min(ret, f(u+w[i], s | (1 << (i-1))));
}
}
return dp[u][s] = ret;
}
int main()
{
cin >> m >> n;
for(int i = 1; i <= m; i++)
cin >> w[i];
for(int i = 1; i <= n; i++)
cin >> p[i];
for(int i = 1; i <= n; i++)
for(int j = 0; j < 1 << m; j++)
dp[i][j] = -1;
printf("%.2lf", f(1, 0));
}