HDU - 2602 Bone Collector
思路
01背包板子题
代码
// 二维数组
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
int f[N][N];
int w[N], v[N];
int main() {
int T;
scanf("%d", &T);
while(T --) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++)
scanf("%d", &w[i]);
for (int i = 1; i <= n; i ++)
scanf("%d", &v[i]);
memset(f, 0, sizeof f);
for (int i = 1; i <= n; i ++) {
for (int j = 0; j <= m; j ++) {
f[i][j] = f[i - 1][j];
if(j >= v[i])
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
}
}
printf("%d\n", f[n][m]);
}
return 0;
}
// 一维数组
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
int f[N];
int w[N], v[N];
int main() {
int T;
scanf("%d", &T);
while(T --) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++)
scanf("%d", &w[i]);
for (int i = 1; i <= n; i ++)
scanf("%d", &v[i]);
memset(f, 0, sizeof f);
for (int i = 1; i <= n; i ++) {
for (int j = m; j >= v[i]; j --) {
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}
printf("%d\n", f[m]);
}
return 0;
}
// 打印路径
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1010;
int f[N][N];
int w[N], v[N];
int path[N][N];
int main() {
int T;
scanf("%d", &T);
while(T --) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++)
scanf("%d", &w[i]);
for (int i = 1; i <= n; i ++)
scanf("%d", &v[i]);
memset(f, 0, sizeof f);
for (int i = 1; i <= n; i ++) {
for (int j = 0; j <= m; j ++) {
f[i][j] = f[i - 1][j];
if(j >= v[i]){
if(f[i - 1][j - v[i]] + w[i] > f[i][j]) {
path[i][j] = 1;
}
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
}
}
}
printf("%d\n", f[n][m]);
for (int i = n, j = m; i > 0, j > 0; i --) {
if(path[i][j]) {
printf("%d ", i);
j -= v[i];
}
}
}
return 0;
}
HDU - 2955 Robberies
思路
状态表示
f
[
i
]
[
j
]
f[i][j]
f[i][j]:考虑前
i
i
i件物品,抢劫
j
j
j元的生存概率
状态计算:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
j
]
,
f
[
i
−
1
]
[
j
−
w
[
i
]
∗
p
)
f[i][j] = max(f[i-1][j], f[i-1][j-w[i] * p)
f[i][j]=max(f[i−1][j],f[i−1][j−w[i]∗p)
初始化:
memset(f, 0, sizeof f), f[0] = 1.0
答案:从取所以物品价值sum
逆序判断是否生存概率大于P, 是则return
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10010;
int n, w[N], sum;
double f[N], P, p[N];
const double eps = 1e-9;
int solve() {
memset(f, 0, sizeof f);
f[0] = 1.0;
for (int i = 1; i <= n; i ++)
for (int j = sum; j >= w[i]; j --) {
f[j] = max(f[j], f[j - w[i]] * p[i]);
}
for (int i = sum; i >= 0; i --)
if(f[i] - P >= eps)
return i;
return 0;
}
int main() {
int T;
scanf("%d", &T);
while(T --) {
cin >> P >> n;
sum = 0, P = 1.0 - P;
for (int i = 1; i <= n; i ++) {
cin >> w[i] >> p[i];
sum += w[i], p[i] = 1.0 - p[i]; // 不被抓的概率
}
cout << solve() << endl;
}
return 0;
}
CodeForces - 366C
思路
DP + 思维
题目要求取出的物品
∑
a
[
i
]
/
∑
b
[
i
]
=
k
\sum a[i] / \sum b[i] = k
∑a[i]/∑b[i]=k
则可以将每个物品的体积看作
a
[
i
]
−
k
∗
b
[
i
]
a[i] - k*b[i]
a[i]−k∗b[i]
因为这个体积有正有负
则答案必须体积 正负抵消为0 才满足题目要求
因此跑一遍01背包, 最后枚举体积求出答案即可
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
int dp1[N], dp2[N];
int a[N], b[N], c[N];
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i ++) {
scanf("%d", &b[i]);
}
memset(dp1, -0x3f, sizeof dp1);
memset(dp2, -0x3f, sizeof dp2);
dp1[0] = 0, dp2[0] = 0;
for (int i = 1; i <= n; i ++) {
c[i] = a[i] - k * b[i];
}
for (int i = 1; i <= n; i ++)
if(c[i] >= 0) {
for (int j = 10000; j >= c[i]; j --) {
dp1[j] = max(dp1[j], dp1[j - c[i]] + a[i]);
}
}
else {
c[i] = -c[i];
for (int j = 10000; j >= c[i]; j --) {
dp2[j] = max(dp2[j], dp2[j - c[i]] + a[i]);
}
}
int ans = -1;
for (int i = 0; i <= 10000; i ++) {
if(dp1[i] == 0 && dp2[i] == 0)
continue;
ans = max(ans, dp1[i] + dp2[i]);
}
printf("%d\n", ans);
return 0;
}