9/7 dp练习+01背包方案数+求背包具体方案
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9/7 dp练习+01背包方案数+求背包具体方案相关的知识,希望对你有一定的参考价值。
01背包方案数
在f[j]表示容量为j时可获得的最大价值的情况下,增加数组c[i]表示容量为i时最优选法的方案数
void fun()
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
if(f[j-v[i]]+w[i]>f[j])
f[j]=f[j-v[i]]+w[i];
c[j]=c[j-v[i]];
else if(f[j-v[i]]+w[i]==f[j])
c[j]=(c[j]+c[j-v[i]])%mod;
cout<<c[m]<<endl;
若增加条件,恰好装满背包的最大价值的方案数?
只需要改变初始化条件即可:
只有恰好装满时,才能直接或间接通过c[0]转移
for(int i=1;i<=n;i++)
f[i]=-inf;
f[0]=0,c[0]=1;
求背包具体方案
void fun()
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int n;i>=1;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 j=m;
for(int i=1;i<=n;i++)
if(j>=v[i]&&f[i][j]==f[i][j-v[i]]+w[i])
cout<<i<<" ";
j-=v[i];
例题:
P1759 通天之潜水
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e5+5;
const int inf=1e18;
const int mod=19980829;
int m,v,n,a[105],b[105],c[105],f[105][205][205];
void solve()
cin>>m>>v>>n;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>c[i];
for(int i=n;i>=1;i--)
for(int j=0;j<=m;j++)
for(int k=0;k<=v;k++)
f[i][j][k]=f[i+1][j][k];
if(j>=a[i]&&k>=b[i])
f[i][j][k]=max(f[i][j][k],f[i+1][j-a[i]][k-b[i]]+c[i]);
cout<<f[1][m][v]<<endl;
int g=m,k=v;
for(int i=1;i<=n;i++)
if(g>=a[i]&&k>=b[i]&&f[i][g][k]==f[i+1][g-a[i]][k-b[i]]+c[i])
cout<<i<<" ";g-=a[i],k-=b[i];
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
P1122 最大子树和
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e6+5;
const int inf=1e18;
const int mod=19980829;
int n,cnt,head[N],a[N],f[N];
struct node
int to,nxt;
e[N*2];
void add(int from,int to)
e[++cnt].to=to;
//e[cnt].w=w;
e[cnt].nxt=head[from];
head[from]=cnt;
void dfs(int u,int fa)
f[u]=a[u];
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
if(f[v]>0)
f[u]=f[u]+f[v];
void solve()
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++)
int u,v;cin>>u>>v;
add(u,v),add(v,u);
dfs(1,0);
int ans=-inf;
for(int i=1;i<=n;i++)
ans=max(ans,f[i]);
cout<<ans<<endl;
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
P1140 相似基因
思路:
1.设计状态:f[i][]j]
表示s1前i个字母和s2前j个字母的最大价值是多少
2.状态转移:s1第i个字母对应s2第j个字母、s1第i个字母对应s2中用_对应、s1中用_对应s2第j个字母
f[i][j]=max(f[i-1][j-1]+d[a[i]][b[j]],f[i-1][j]+d[a[i]][5],f[i][j-1]+d[5][b[j]]);
3.将4个字母转移为数字1、2、3、4,打表表示对应关系
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e5+5;
const int inf=1e18;
const int mod=19980829;
int n,m,a[105],b[105],f[105][105];
string s1,s2;
int d[6][6]=0,0,0,0,0,0,
0,5,-1,-2,-1,-3,
0,-1,5,-3,-2,-4,
0,-2,-3,5,-2,-2,
0,-1,-2,-2,5,-1,
0,-3,-4,-2,-1,0
;
void solve()
cin>>n>>s1>>m>>s2;
for(int i=1;i<=n;i++)
if(s1[i-1]=='A') a[i]=1;
else if(s1[i-1]=='C') a[i]=2;
else if(s1[i-1]=='G') a[i]=3;
else a[i]=4;
for(int i=1;i<=m;i++)
if(s2[i-1]=='A') b[i]=1;
else if(s2[i-1]=='C') b[i]=2;
else if(s2[i-1]=='G') b[i]=3;
else b[i]=4;
for(int i=1;i<=n;i++)
f[i][0]=f[i-1][0]+d[a[i]][5];
for(int i=1;i<=m;i++)
f[0][i]=f[0][i-1]+d[5][b[i]];
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
f[i][j]=max(f[i-1][j-1]+d[a[i]][b[j]],f[i-1][j]+d[a[i]][5],f[i][j-1]+d[5][b[j]]);
cout<<f[n][m]<<endl;
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
P1564 膜拜
思路:
1.可想到1和2的人数可抵消,因此将2转化为-1,使用前缀和记录。
2.若abs(sum[i]-sum[j-1])==i-j+1
说明有连续的人数,若abs(sum[i]-sum[j-1])<=m
也符合题意
3.转移方程:f[i]=min(f[i],f[j-1]+1)
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=以上是关于9/7 dp练习+01背包方案数+求背包具体方案的主要内容,如果未能解决你的问题,请参考以下文章
[01背包] 背包问题求方案数(01背包+求方案数+求最优解方案数+思维)