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背包+求方案数+求最优解方案数+思维)

动态规划专题

背包问题求具体方案

[H背包] lc1449. 数位成本和为目标值的最大数字(背包求具体方案+状态定义+边界情况)

背包输出方案数

背包输出方案数