目录
- #include
- using namespace std;
- const int N=1e3+10;
- int f[N];//滚动数组优化后的
- int main()
- {
- int n,m;
- cin>>m>>n;
- for(int i=0;i
- {
- int v,w;
- cin>>v>>w;
- for(int j=m;j>=v;j--) f[j]=max(f[j],f[j-v]+w);//从打到小滚动,要么选当前数,要么不选
- }
- cout<
- return 0;
- }
2. 装箱问题
- #include
- using namespace std;
- const int N=2e4+10;
- int f[N];
- int main()
- {
- int n,m;
- cin>>m>>n;
- for(int i=0;i
- {
- int v;
- cin>>v;
- for(int j=m;j>=v;j--) f[j]=max(f[j],f[j-v]+v);
- }
- cout<
- return 0;
- }
3.开心的金明
- #include
- using namespace std;
- const int N=3e4+10;
- int f[N];
- int main()
- {
- int n,m;
- cin>>m>>n;
- for(int i=1;i<=n;i++)
- {
- int v,w;
- cin>>v>>w;
- for(int j=m;j>=v;j--)
- f[j]=max(f[j],f[j-v]+v*w);
- }
- cout<
- return 0;
- }
二维背包
1. 二维费用的背包问题

- #include
- using namespace std;
- const int N=1e4+10;
- int f[N][N];
- int main()
- {
- int n,b,c;
- scanf("%d%d%d",&n,&b,&c);
- for(int i=1;i<=n;i++) {
- int v,m,w;
- scanf("%d%d%d",&v,&m,&w);
- for(int j=b;j>=v;j--)//优化一维
- for(int k=c;k>=m;k--)
- f[j][k]=max(f[j][k],f[j-v][k-m]+w);//要么选第i个,要么不选第i个
- }
- printf("%d",f[b][c]);
- return 0;
- }
2. 宠物小精灵之收服

初始状态:f[0][0][0]
目标状态:f[n][m][t - 1] (皮神不能 再起不能 才算抓住那个 宝可梦 )
- #include
- #include
- #include
-
- using namespace std;
-
- const int N = 110, M = 1010, K = 510;
-
- int n, m, t;
- int v1[N], v2[N];
- int f[M][K];
-
- int main()
- {
- //input
- cin >> m >> t >> n;
- for (int i = 1; i <= n; ++ i) cin >> v1[i] >> v2[i];
-
- //dp
- for (int i = 1; i <= n; ++ i)
- {
- for (int j = m; j >= v1[i]; -- j)
- {
- for (int k = t - 1; k >= v2[i]; -- k)
- {
- f[j][k] = max(f[j][k], f[j - v1[i]][k - v2[i]] + 1);
- }
- }
- }
-
- //output
- cout << f[m][t - 1] << " ";
- //找到满足最大价值的所有状态里,第二维费用消耗最少的
- int cost_health = t;
- for (int k = 0; k <= t - 1; ++ k)
- {
- if (f[m][k] == f[m][t - 1])
- {
- cost_health = min(cost_health, k);
- }
- }
- cout << t - cost_health << endl;
- return 0;
- }
-
3.潜水员【01背包问题+二维费用'不少于'问题】

- #include
- using namespace std;
- const int N=22,M=80;
- int f[N][M];
- int main()
- {
- int V1,V2,n;
- cin>>V1>>V2>>n;
- memset(f,0x3f,sizeof f);//求最小值要把除初始状态以外的所有状态初始化为+∞
- f[0][0]=0;//表示前0个物品选第一个体积V1至少为0的,第二个体积V2至少为0的价值为0,而其他不存在初始化为正无穷,表示更新最小值不用到他
- for(int i=1;i<=n;i++)
- {
- int v1,v2,w;
- cin>>v1>>v2>>w;
- for(int j=V1;j>=0;j--)
- for(int k=V2;k>=0;k--)
- f[j][k]=min(f[j][k],f[max(0,j-v1)][max(0,k-v2)]+w);//假如小于0,就让他等于0
- }
- cout<
//输出至少为V1和V2的最小价值 - return 0;
- }
分组背包
机器分配【分组背包+背包DP输出方案—拓扑图分析】

- #include
- using namespace std;
- const int N=15,M=20;
- int f[N][M],v[N][M],w[M];//用v存第i组物品的各物品数的分别价值,w存的是每组物品分别用到那个
- int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- cin>>v[i][j];
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- for(int k=0;k<=j;k++)
- f[i][j]=max(f[i-1][k]+v[i][j-k],f[i][j]);
- cout<
- for(int i=n,j=m;i>=1;i--)
- for(int k=0;k<=j;k++)
- {
- if(f[i][j]==f[i-1][k]+v[i][j-k])
- {
- w[i]=j-k;
- j=k;
- break;
- }
-
- }
-
- for(int i=1;i<=n;i++)
- cout<" "<
- }
-
- #include
- using namespace std;
- const int N=15,M=20;
- int f[N][M],v[N][M],flag[N][M];//存每个公司被分配的设备数
- void dfs(int x,int y)
- {
- if(x==0)return;
- dfs(x-1,y-flag[x][y]);
- cout<
" "< - }
- int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- cin>>v[i][j];
- for(int i=1;i<=n;i++)
- for(int j=1;j<=m;j++)
- for(int k=0;k<=j;k++)
- {
- if(f[i][j]
-1][k]+v[i][j-k]) - {
- f[i][j]=f[i-1][k]+v[i][j-k];
- flag[i][j]=j-k;//存第i个公司被分配的j-k个设备
- }
-
- }
- cout<
- dfs(n,m);
- }
-
-
有依赖的背包问题
有依赖的背包问题【有依赖背包DP+子物品体积集合划分】

- #include
- #include
-
- using namespace std;
-
- const int N = 110;
-
- int n, m, root;
- int h[N], e[N], ne[N], idx;
- int v[N], w[N];
- int f[N][N];
-
-
- void add(int a, int b)
- {
- e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
- }
- void dfs(int u)
- {
- //先枚举所有状态体积小于等于j-v[u]的所有子节点们能够获得的最大价值
- for (int i = h[u]; i!=-1; i = ne[i])
- {
- int son = e[i];
- dfs(son); //从下往上算,先计算子节点的状态
- for (int j = m - v[u]; j >= 0; -- j) //枚举所有要被更新的状态
- {
- for (int k = 0; k <= j; ++ k) //枚举该子节点在体积j下能使用的所有可能体积数
- {
- f[u][j] = max(f[u][j], f[u][j - k] + f[son][k]);
- }
- }
- }
- //最后选上第u件物品
- for (int j = m; j >= v[u]; -- j) f[u][j] = f[u][j - v[u]] + w[u];
- for (int j = 0; j < v[u]; ++ j) f[u][j] = 0; //清空没选上u的所有状态
- }
- int main()
- {
- memset(h, -1, sizeof h);
- cin >> n >> m;
- for (int i = 1; i <= n; ++ i)
- {
- int p;
- cin >> v[i] >> w[i] >> p;
- if (p == -1) root = i;
- else add(p, i);
- }
- dfs(root);
- cout << f[root][m] << endl;
- return 0;
- }
金明的预算方案【有依赖背包DP+分组背包集合划分】
- #include
- using namespace std;
- #define x first
- #define y second
- typedef pair<int,int> PII;
- const int N=65,M=32010;
- int f[M],v,w,q;
- PII zhu[N];//用来存主件
- vector
fu[N];//用来附件主件 - int main()
- {
- int m,n;
- cin>>m>>n;
- for(int i=1;i<=n;i++)
- {
- cin>>v>>w>>q;
- if(!q)
- zhu[i]={v,v*w};//把主件放进去
- else
- fu[q].push_back({v,v*w});//把附件存该主件下
- }
- for(int i=1;i<=n;i++)
- {
- if(zhu[i].x)
- for(int j=m;j>=0;j--)
- {
-
- int t=fu[i].size();
- for(int k=0;k<1<
//二进制枚举在附件有t个的情况下的选法 - {
- int v=zhu[i].x,w=zhu[i].y;
- for(int u=0;u
//枚举位数,判断该位数是否为1,为1则选该附件 - if(k>>u&1) v+=fu[i][u].x,w+=fu[i][u].y;
- if(j>=v) f[j]=max(f[j],f[j-v]+w);//假如合法,则转移
- }
- }
- }
- cout<
- }
背包问题求解方案数
1.背包问题求解方案数 【背包DP求最优方案总数】

- #include
- using namespace std;
- const int N=1010,mod=1e9+7;
- int f[N],cnt[N];
- int main()
- {
- int n,m;
- 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])
- {
- cnt[j]=cnt[j-v];
- f[j]=value;
- }
- else if(value==f[j])
- {
- cnt[j]=(cnt[j]+cnt[j-v])%mod;
- }
- }
- }
- cout<
- }
2. 数字组合【01背包求解方案数】
分析
对于本题我们可以把每个 正整数 看作是一个 物品
正整数 的值就是 物品 的 体积
我们方案选择的 目标 是最终 体积 恰好为 m 时的 方案数
于是本题就变成了 01背包求解方案数 的问题了
闫氏DP分析法
初始状态:f[0][0]
目标状态:f[n][m]

- #include
- using namespace std;
- const int N=110,M=10010;
- int f[M],v[N];
- int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- cin>>v[i];
- f[0]=1;
- for(int i=1;i<=n;i++)
- for(int j=m;j>=v[i];j--)
- f[j]+=f[j-v[i]];
- cout<
- }
3.买书【完全背包求解方案数+朴素优化】
初始状态:f[0][0]
目标状态:f[n][m]

Code(朴素版)
最坏时间复杂度:O(n^2×m)
- #include
-
- using namespace std;
-
- const int N = 5, M = 1010;
-
- int n = 4, m;
- int v[N] = {0, 10, 20, 50, 100};
- int f[N][M];
-
- int main()
- {
- //input
- cin >> m;
-
- //dp
- f[0][0] = 1;
- for (int i = 1; i <= n; ++ i)
- {
- for (int j = 0; j <= m; ++ j)
- {
- for (int k = 0; v[i] * k <= j; ++ k)
- {
- f[i][j] += f[i - 1][j - v[i] * k];
- }
- }
- }
-
- //output
- cout << f[n][m] << endl;
-
- return 0;
- }

- #include
-
- using namespace std;
-
- const int N = 5, M = 1010;
-
- int n = 4, m;
- int v[N] = {0, 10, 20, 50, 100};
- int f[M];
-
- int main()
- {
- //input
- cin >> m;
-
- //dp
- f[0] = 1;
- for (int i = 1; i <= n; ++ i)
- {
- for (int j = v[i]; j <= m; ++ j)
- {
- f[j] += f[j - v[i]];
- }
- }
-
- //output
- cout << f[m] << endl;
-
- return 0;
- }
-
4. 货币系统【完全背包求解方案数】

- #include
-
- using namespace std;
-
- typedef long long LL;
-
- const int N = 20, M = 3010;
-
- int n, m;
- int v[N];
- LL f[M];
-
- int main()
- {
- cin >> n >> m;
- for (int i = 1; i <= n; ++ i) cin >> v[i];
- f[0] = 1;
- for (int i = 1; i <= n; i++)
- {
- for (int j = v[i]; j <= m; j++)
- {
- f[j] += f[j - v[i]];
- }
- }
- cout << f[m] << endl;
- return 0;
- }
-
5.货币系统【完全背包求解最大无关向量组个数】

- #include
- using namespace std;
-
- //这题是一道线性代数问题
- //求解一个向量组的秩(最大无关向量组的向量个数)
- //但是代码写起来就是一个模拟筛的过程
- //从小到大,先查看当前数有没有被晒掉,
- //1)如果没有就把它加入到最大无关向量组中,并把他以及他和此前的硬币的线性组合都筛掉
- //2)如果有就不理会
- //即就是在完全背包求方案数的过程中,统计那些初始没有方案数的物品
- //这样就变成一个完全背包问题了
-
- const int N = 110, M = 25010;
- int n;
- int v[N];
- bool f[M];
-
- int main()
- {
- int T = 1;
- cin >> T;
- while (T -- )
- {
- cin >> n;
- for (int i = 1; i <= n; ++ i) cin >> v[i];
- sort(v + 1, v + n + 1);//排序的原因见之前的分析
-
- //我们只需统计所有物品的体积是否能被其他的线性表出
- //因此背包的体积只需设置为最大的物品体积即可
- //res用来记录最大无关向量组的个数
- int m = v[n], res = 0;
- memset(f, 0, sizeof f);
- f[0] = true; //状态的初值
- for (int i = 1; i <= n; ++ i)
- {
- //如果当前物品体积被之前的物品组合线性筛掉了,则它是无效的
- if (f[v[i]]) continue;
- //如果没有被筛掉,则把它加入最大无关向量组
- res ++ ;
- //筛掉当前最大无关向量组能线性表示的体积
- for (int j = v[i]; j <= m; ++ j)
- {
- f[j] |= f[j - v[i]];
- }
- }
- //输出最大无关向量组的向量个数
- cout << res << endl;
- }
- return 0;
- }
背包问题求具体方案
背包问题求具体方案【01背包 + 背包DP输出方案】
- #include
- using namespace std;
- const int N=1010;
- int f[N][N];
- int v[N],w[N];
- int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- cin>>v[i]>>w[i];
- for(int i=n;i;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][j],f[i+1][j-v[i]]+w[i]);
- }
- int i=1,j=m;
- while(i<=n)
- {
- if(j>=v[i]&&f[i+1][j-v[i]]+w[i]>=f[i+1][j])
- {
- cout<" ";
- j-=v[i];
- i++;
- }
- else i++;
- }
-
-
- }
多重背包问题
1. 多重背包问题 III【单调队列优化+图示】
二维朴素版
- #include
-
- using namespace std;
-
- const int N = 1010, M = 20010;
-
- int n, m;
- int v[N], w[N], s[N];
- int f[N][M];
- int q[M];
-
- int main()
- {
- cin >> n >> m;
- for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
- for (int i = 1; i <= n; ++ i)
- {
- for (int r = 0; r < v[i]; ++ r)
- {
- int hh = 0, tt = -1;
- for (int j = r; j <= m; j += v[i])
- {
- while (hh <= tt && j - q[hh] > s[i] * v[i]) hh ++ ;
- while (hh <= tt && f[i - 1][q[tt]] + (j - q[tt]) / v[i] * w[i] <= f[i - 1][j]) -- tt;
- q[ ++ tt] = j;
- f[i][j] = f[i - 1][q[hh]] + (j - q[hh]) / v[i] * w[i];
- }
- }
- }
- cout << f[n][m] << endl;
- return 0;
- }
-
-
一维优化
拷贝数组
- #include
- #include
-
- using namespace std;
-
- const int N = 1010, M = 20010;
-
- int n, m;
- int v[N], w[N], s[N];
- int f[M], g[M];
- int q[M];
-
- int main()
- {
- cin >> n >> m;
- for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
- for (int i = 1; i <= n; ++ i)
- {
- memcpy(g, f, sizeof g);
- for (int r = 0; r < v[i]; ++ r)
- {
- int hh = 0, tt = -1;
- for (int j = r; j <= m; j += v[i])
- {
- while (hh <= tt && j - q[hh] > s[i] * v[i]) hh ++ ;
- while (hh <= tt && g[q[tt]] + (j - q[tt]) / v[i] * w[i] <= g[j]) -- tt;
- q[ ++ tt] = j;
- f[j] = g[q[hh]] + (j - q[hh]) / v[i] * w[i];
- }
- }
- }
- cout << f[m] << endl;
- return 0;
- }
滚动数组
- #include
-
- using namespace std;
-
- const int N = 1010, M = 20010;
-
- int n, m;
- int v[N], w[N], s[N];
- int f[2][M];
- int q[M];
-
- int main()
- {
- cin >> n >> m;
- for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
- for (int i = 1; i <= n; ++ i)
- {
- for (int r = 0; r < v[i]; ++ r)
- {
- int hh = 0, tt = -1;
- for (int j = r; j <= m; j += v[i])
- {
- while (hh <= tt && j - q[hh] > s[i] * v[i]) hh ++ ;
- while (hh <= tt && f[(i - 1) & 1][q[tt]] + (j - q[tt]) / v[i] * w[i] <= f[(i - 1) & 1][j]) -- tt;
- q[ ++ tt] = j;
- f[i & 1][j] = f[(i - 1) & 1][q[hh]] + (j - q[hh]) / v[i] * w[i];
- }
- }
- }
- cout << f[n & 1][m] << endl;
- return 0;
- }
-
庆功会【多重背包朴素版】
朴素写法
-
- #include
- using namespace std;
- const int N=510,M=6010;
- int f[N][M],v[N];
- int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- {
- int v,w,s;
- cin>>v>>w>>s;
- for(int j=1;j<=m;j++)
- for(int k=0;k<=s&&k*v<=j;k++)
- f[i][j]=max(f[i][j],f[i-1][j-k*v]+k*w);
- }
- cout<
- }
一维优化
- #include
- using namespace std;
- const int N=510,M=6010;
- int f[M],v[N];
- int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=1;i<=n;i++)
- {
- int v,w,s;
- cin>>v>>w>>s;
- for(int j=m;j>=v;j--)
- for(int k=0;k<=s&&k*v<=j;k++)
- f[j]=max(f[j],f[j-k*v]+k*w);
- }
- cout<
- }
混合背包问题
混合背包问题【混合背包DP模型】

- #include
- using namespace std;
- const int N=1010;
- int f[N];
- struct Thing
- {
- int kind;
- int v,w;
- };
- vector
things; - int main()
- {
- int n,m;
- cin>>n>>m;
- for(int i=0;i
- {
- int v,w,s;
- cin>>v>>w>>s;
- if(s<0) things.push_back({-1,v,w});
- else if(s==0) things.push_back({0,v,w});
- else
- {
- for(int k=1;k<=s;k*=2)
- {
- s-=k;
- things.push_back({-1,v*k,w*k});
- }
- if(s>0)things.push_back({-1,v*s,w*s});
- }
- }
- for(auto thing : things)
- {
- if(thing.kind<0)
- for(int j=m;j>=thing.v;j--)
- f[j]=max(f[j],f[j-thing.v]+thing.w);
- else
- for(int j=thing.v;j<=m;j++)
- f[j]=max(f[j],f[j-thing.v]+thing.w);
- }
- cout<
- }
其他背包问题
能量石【01背包 + 贪心(邻项交换)】
- #include
- using namespace std;
- const int N=110,M=1e5+10;
- int f[M];
- struct Node
- {
- int s,e,l;
- bool operator<(const Node &x)const //重载小于号
- {
- return s*x.l
- }
- }a[N];
- void solve()
- {
- int t=0;//存储总时间
- //求恰好的背包DP,为了保证状态都是从起点转移的,要把非起点初始化为无穷大以避免转移
- memset(f, -0x3f, sizeof f);
- f[0] = 0;
- int n;
- cin>>n;
- for(int i=1;i<=n;i++)
- {
- cin>>a[i].s>>a[i].e>>a[i].l;
- m+=a[i].s;
- }
- sort(a+1,a+n+1);
- for(int i=1;i<=n;i++)
- {
- for(int j=m;j>=a[i].s;j--)
- {
- f[j]=max(f[j],f[j-a[i].s]+max(0,a[i].e-(j-a[i].s)*a[i].l));
- }
- }
- int res=0;
- for(int i=1;i<=m;i++) res=max(res,f[i]);
- cout<
- }
- int main()
- {
- int t;
- cin>>t;
- for(int i=1;i<=t;i++)
- {
- cout<<"Case #"<": ";
- solve();
- }
- }
-
相关阅读:
BP神经网络算法基本原理,bp神经网络的算法步骤
【教程】uni-app iOS打包解决profile文件与私钥证书不匹配问题
聚已内酯共聚肝素 Heparin-PCL/聚乳酸-羟基乙酸共聚物-b-肝素 Heparin-PLGA/聚乳酸-b-肝素 Heparin-PLA
C++基础语法(继承)
外贸人如何把握客户跟进频率?
Springboot毕设项目基于SpringBoot的图片网站f3yv9(java+VUE+Mybatis+Maven+Mysql)
基于信息融合的风电机组关键部件状态识别
Java高并发编程实战3,Java内存模型与Java对象结构
HTTP与SOCKS-哪种协议更适合您的代理需求?
如何检测Windows服务停止后自动启动?自动运行.bat批处理文件?
-
原文地址:https://blog.csdn.net/m0_64378422/article/details/127769279