- chjshen 的博客
20240315背包讲义
- 2024-3-15 11:02:48 @
01背包
朴素
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 35;
int n, v, a[N];
int dp[N][20005];
int f[20005];
int main(void)
{
cin >> v >> n;
for(int i = 1; i <= n ;i ++) cin >> a[i];
for(int i = 1; i <= n; i++)
{
for(int j = v; j >= a[i]; j--)
// for(int j = 0; j <= v; j++)
{
f[j] = max(f[j], f[j - a[i]] + a[i]);
// dp[i][j] = dp[i - 1][j];
// if(j >= a[i])
// dp[i][j] = max(dp[i][j], dp[i- 1][j - a[i]] + a[i]);
}
}
cout << v - f[v];
return 0;
}
空间压缩
j逆向
/* created by chjshen, date: 2024-03-16 01:33 */
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 25, M = 3E4 + 5;
int n, m, v[N], p[N], c[N];
int dp[M];
void handle(void)
{
for (int i = 1; i <= n; i++)
for (int j = m; j >= v[i]; j--)
{
dp[j] = max(dp[j], dp[j - v[i]] + c[i]);
}
cout << dp[m];
}
void initInput(void)
{
ios::sync_with_stdio(0);
cin >> m >> n;
for (int i = 1; i <= n; i++)
{
cin >> v[i] >> p[i];
c[i] = v[i] * p[i];
}
}
int main(void)
{
initInput();
handle();
return 0;
}
完全背包
朴素
空间压缩
j正向
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 35, M = 300;
int n, m, w[N], c[N];
int dp[N][M];
void dp1()
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i - 1][j];
if(j >= w[i]) dp[i][j] = max(dp[i][j], dp[i][j - w[i]] + c[i]);
// for(int k = 1; k <= j / w[i]; k++)
// {
// dp[i][j] = max(dp[i][j], dp[i - 1][j - k * w[i]] + k * c[i]);
// }
}
}
cout << "max=" << dp[n][m];
}
int f[M];
void dp2()
{
for(int i = 1; i <= n; i++)
{
for(int j = w[i]; j <= m; j++)
{
f[j] = max(f[j], f[j - w[i]] + c[i]);
}
}
cout << "max=" << f[m];
}
int main(void)
{
cin >> m >> n;
for(int i = 1; i <= n; i++) cin >> w[i] >> c[i];
// dp1();
dp2();
return 0;
}
最小/少问题
/* created by chjshen, date: 2024-03-15 14:18 */
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1e6 + 5;
int n;
int cnt;
int dp[N];
int a[N];
void handle(void)
{
for (int i = 1; i <= cnt; i++)
{
for (int j = a[i]; j <= n; j++)
{
dp[j] = min(dp[j], dp[j - a[i]] + 1);
}
}
cout << dp[n];
}
void initInput(void)
{
ios::sync_with_stdio(0);
cin >> n;
cnt = 1, a[1] = 1;
int six = 1, nine = 1;
while (six <= n)
{
six *= 6;
if (six <= n) a[++cnt] = six;
}
while(nine <= n)
{
nine *= 9;
a[++cnt] = nine;
}
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
}
int main(void)
{
initInput();
handle();
return 0;
}
多重背包
转换成01背包来解决,二进制拆分优化
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 101, M = 1e7 + 5;
int n = 10;
int m, a[N],cnt, c[N];
int dp[M];
int main(void)
{
cin >> m;
a[1] = 1;
for(int i = 2; i <= n; i++)
{
a[i] = a[i - 1] * i;
}
cnt = n;
for(int i = 1; i <= n; i++)
{
c[i] = 1;
int p = 2, q = 100;
while(p <= q)
{
q -= p;
a[++cnt] = p * a[i];
c[cnt] = p;
p *= 2;
}
if(q)
a[++cnt] = a[i] * q, c[cnt] = q;
}
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for(int i = 1; i <= cnt; i++)
{
for(int j = m; j >= a[i]; j--)
{
dp[j] = min(dp[j], dp[j - a[i]] + c[i]);
}
}
cout << dp[m];
return 0;
}
恰好问题
背包与方案数
ac代码:
/* created by chjshen, date: 2024-03-17 09:53 */
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 105;
const int M = 1e4 + 5;
int a[N], n, m;
int dp[M];
void handle(void)
{
dp[0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = m; j >= a[i]; j--)
{
dp[j] = dp[j] + dp[j - a[i]];
}
}
cout << dp[m] << endl;
}
void initInput(void)
{
ios::sync_with_stdio(0);
cin >> n;
cin >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
}
int main(void)
{
initInput();
handle();
return 0;
}
分组背包
和01背包几乎一样,多一层循环一个组的物品。
混合背包
想各种办法转换成01背包:多重转01背包的思路,完全背包也可以转成01背包。
二维费用背包
多一维即可,dp[i][j][k] 表示前i个物品放入容量(第一维)为j,重量(另一维)为k的背包中的最大值。