机器分配
思路:
分组背包+路径遍历
#include <iostream>
using namespace std;
const int N = 15,M = 25;
int f[N][M];
int a[N][M];
int way[N];
int main() {
int n,m;
cin>>n>>m;;
for(int i = 1;i<=n;i++)
for(int j = 1;j<=m;j++)
cin>>a[i][j];
for(int i = 1;i<=n;i++){
for(int j = 0;j<=m;j++){
for(int k = 0;k<=j;k++){
f[i][j] = max(f[i][j],f[i-1][j-k]+a[i][k]);
}
}
}
cout<<f[n][m]<<endl;
int j = m;
for(int i = n;i>0;i--){
for(int k = 0;k<=j;k++){
if(f[i][j]==f[i-1][j-k]+a[i][k])
{
way[i] = k;
j -= k;
break;
}
}
}
for(int i = 1;i<=n;i++){
cout<<i<<' '<<way[i]<<endl;
}
return 0;
}
金明的预算计划
分组背包应用,每一个主件所附带的附件的每一种情况就算是一个背包里面的一种情况,变成一种位运算求方案!
#include <iostream>
#include <vector>
using namespace std;
typedef pair<int,int> PII;
const int M = 32010,N = 65;
int f[M];
vector<PII> a[N];
PII master[N];
int main() {
int n,m;
//钱和物品的个数
cin>>m>>n;
for(int i = 1;i<=n;i++){
int v,p,q;
scanf("%d%d%d",&v,&p,&q);
if(!q){
master[i] = {v,v*p};
}
else{
a[q].push_back({v,v*p});
}
}
for(int i = 1;i<=n;i++){
if(master[i].first){
for(int j = m;j;j--){
for(int k = 0;k< 1<< a[i].size();k++){
int v= master[i].first,w = master[i].second;
if(j>=v) f[j] = max(f[j],f[j-v]+w);
for(int u = 0;u<a[i].size();u++){
if(k>>u&1){
v+=a[i][u].first;
w+=a[i][u].second;
}
if(j>=v) f[j] = max(f[j],f[j-v]+w);
}
}
}
}
}
cout<<f[m];
return 0;
}
货币系统
思路:
求出极大非线性数组,如果能够被其他的数表示的数就不选
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 105,M = 25005;
int f[M];
int a[N];
int main() {
int T;
cin>>T;
while(T--){
int n;
cin>>n;
for(int i = 1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
// cout<<a[1]<<' ';
memset(f,0,sizeof f);
int m = a[n];
f[0] = 1;
int res = 0;
for(int i = 1;i<=n;i++){
if(f[a[i]]==0) res++;
for(int j = a[i];j<=m;j++){
f[j] += f[j-a[i]];
}
}
cout<<res<<endl;
}
return 0;
}
混合背包
思路:
有三种背包,多重背包使用二进制优化,也可以使用单调队列优化。
#include <iostream>
using namespace std;
const int N = 1e3+10;
int f[N];
int main() {
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++){
int v,w,s;
scanf("%d%d%d",&v,&w,&s);
if(s==0)
for(int j = v;j<=m;j++){
f[j] = max(f[j],f[j-v]+w);
}
else if(s==-1)
for(int j = m;j>=v;j--)
f[j] = max(f[j],f[j-v]+w);
else
{
int k = 1;
pair<int,int> a[N];
int cnt = 0;
while(k<=s){
s-=k;
a[cnt++] = {v*k,w*k};
k++;
}
if(s>0)
a[cnt++] = {k*v,k*w};
for(int j = 0;j<cnt;j++){
for(int k = m;k>=a[j].first;k--){
f[k] = max(f[k],f[k-a[j].first]+a[j].second);
}
}
}
}
cout<<f[m];
return 0;
}
有依赖的背包问题
将每一个子树的体积作为背包的转移体积,然后划分。
#include <iostream>
#include <vector>
using namespace std;
const int N = 105;
vector<int> a[N];
int f[N][N],v[N],w[N];
int n,m;
void dfs(int u){
for(auto i:a[u]){
dfs(i);
//分组背包
for(int j = m-v[u];j>=0;j--){
for(int k = 0;k<=j;k++)
f[u][j] = max(f[u][j],f[u][j-k]+f[i][k]);
}
}
for(int i = m;i>=v[u];i--) f[u][i] = f[u][i-v[u]]+w[u];
for(int i = 0;i<v[u];i++) f[u][i] = 0;
}
int main() {
cin>>n>>m;
int root ;
for(int i = 1;i<=n;i++){
int p;
cin>>v[i]>>w[i]>>p;
if(p==-1)
root = i;
else
a[p].push_back(i);
}
dfs(root);
cout<<f[root][m];
return 0;
}