一、背包问题求方案数
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int f[N];
int cnt[N];
int n,m;
const int mod = 1e9 + 7;
int main()
{
int res = 0;
cin >> n >> m;
for(int i = 0;i <= m;i ++) cnt[i] = 1;//背包里面什么都不装也是一种方案
for(int i = 1;i <= n;i ++)
{
int v,w;
cin >> v >> w;
for(int j = m;j >= v;j --)
{
int value = f[j - v] + w;
if(value > f[j])
{
f[j] = value;
cnt[j] = cnt[j - v];
}
else if(value == f[j])
{
cnt[j] = (cnt[j] + cnt[j - v]) % mod;
}
}
}
cout << cnt[m];
return 0;
}
二、背包问题求具体方案
这里和01背包不一样的地方就是01背包只需要得到价值最大并且背包恰好装满的情况,但是这里能量石会随着时间的耗散,能量逐渐减小,有可能为负值,所以你的最优解不一定是吃完所有的能量石,而是吃到某一个能量石的时候,你所获得的能量最大,后面的能量石也就是没吃
这里用到了贪心,也就是两个能量石不互换的话,吃完两个能量石所获得的能量最大,为什么呢?
Ei−t∗Li+Ej−(t+Si)∗Lj>=Ej−t∗Lj+Ei−(t+Sj)∗Li
整理后:
Si∗Lj<=Sj∗Li
𝑆𝑖∗𝐿𝑗<=𝑆𝑗∗𝐿𝑖
我们可以把跟𝑖
有关的放到一边,调整一下:
Si/Li<=Sj/Lj
#include <iostream>
using namespace std;
// 定义常数N,表示物品的最大数量
const int N = 1010;
// 定义全局变量
int n, m; // n表示物品数量,m表示背包的最大承重
int v[N], w[N]; // v[i]表示第i个物品的重量,w[i]表示第i个物品的价值
int f[N][N]; // f[i][j]表示前i个物品在总重量不超过j的情况下可以达到的最大价值
int main()
{
// 输入物品数量n和背包最大承重m
cin >> n >> m;
// 输入每个物品的重量和价值
for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
// 动态规划求解0-1背包问题
// 注意这里我们从后往前遍历物品,是为了保证每个物品只被考虑一次(即0-1背包的特点)
for (int i = n; i >= 1; i -- )
for (int j = 0; j <= m; j ++ )
{
// 如果不选择当前物品i,则最大价值等于前一个物品i+1在相同重量下的最大价值
f[i][j] = f[i + 1][j];
// 如果选择当前物品i,并且当前重量j可以容纳该物品,则比较选择和不选择该物品的价值,取较大者
if (j >= v[i]) f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);
}
// 输出最优解中所包含的物品
// 这里我们从背包的最大承重m开始,逆向查找选择了哪些物品
int j = m;
for (int i = 1; i <= n; i ++ )
// 如果选择当前物品i可以使得总价值最大,则输出该物品编号,并更新剩余重量
if (j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i])
{
cout << i << ' ';
j -= v[i];
}
return 0;
}
三、能量石
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110,M = 1e5 + 10;
int n,cnt;
int g[M];
struct Stone
{
int s,e,l;
bool operator < (const Stone& w) const
{
return s * w.l < w.s * l;
}
}f[N];
int main()
{
int T;
cin >> T;
while(T --)
{
memset(g, -0x3f, sizeof g);
cin >> n;
int m = 0;
for(int i = 1;i <= n;i ++)
{
int s,e,l;
cin >> s >> e >> l;
f[i] = {s,e,l};
m += s;
}
sort(f + 1, f + n + 1);
g[0] = 0;
for(int i = 1;i <= n;i ++)
{
for(int j = m;j >= f[i].s;j --)
g[j] = max(g[j], g[j - f[i].s] + max(0, f[i].e - (j - f[i].s) * f[i].l) );
}
int res = 0;
for(int i = 1;i <= m;i ++) res = max(res, g[i]);
printf("Case #%d: %d\n", ++cnt, res);
}
return 0;
}
四、金明的预算方案
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N = 65, M = 32100;
typedef pair<int,int> PII;
PII master[N];//主件
vector<PII> servent[N];//副件
int f[M];
int n,m;
#define v first
#define w second
int main()
{
cin >> m >> n;
for (int i = 1; i <= n; i ++ )
{
int v, p, q;
cin >> v >> p >> q;
p *= v;
if (!q) master[i] = {v, p};
else servent[q].push_back({v, p});
}
for (int i = 1; i <= n; i ++ )
for(int u = m;u >= 0;u --)
{
for(int j = 0;j < 1 << servent[i].size();j ++)
{
int w = master[i].w, v = master[i].v;
for(int k = 0;k < servent[i].size();k ++)
{
if(j >> k & 1)
{
w += servent[i][k].w;
v += servent[i][k].v;
}
}
if(u >= v) f[u] = max(f[u], f[u - v] + w);
}
}
cout << f[m];
return 0;
}