【kuangbin计划】简单DP(4-6题 java/c++双语言详细解析)

目录

4549. 做作业 - 状态dp

4550. 超级跳跳跳 - 最长上升子序列dp

4551. 猪猪存钱罐 - 完全背包问题

1、c++

 2、java 这版vjudge格式被卡 acw可以过


4549. 做作业 - 状态dp

4549. 做作业 - AcWing题库

这题对我来说很难,写个题解理解一下,拓展做题思路+提高理解能力

题目:

 

思路:

f[i]完成作业状态为i的最小扣分

详见代码注释部分

#include <iostream>
#include <algorithm>
#include <cstring>
#include <stack>
using namespace std;

const int N=16;
int n;
struct node
{
    string lesson;
    int ddl,t;
}a[N];

int f[1<<N]; //f[i]完成作业状态为i的最小扣分
int tt[1<<N];
int ans[1<<N];

void solve()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i].lesson>>a[i].ddl>>a[i].t;
    
    memset(f,0x3f,sizeof f);
    memset(ans,0,sizeof ans);
    memset(tt,0,sizeof tt);
    
    for(int i=0;i<1<<n;i++) //枚举所有可能的完成作业状态 比如110表示第一科没完成 第二科和第三科完成
        for(int j=0;j<n;j++)
            if(i>>j&1) tt[i]+=a[j].t; //预处理每一种状态花费的总时间
    
    f[0]=0;     
    for(int i=0;i<1<<n;i++)
        for(int j=0;j<n;j++)
            if(!(i>>j&1)) //如果这一科未完成(该位为0)
            {
                int pre=i; //记录未改变时状态
                int now=i+(1<<j); //将这一科完成(该位变为1)
                int score=max(0,tt[pre]+a[j].t-a[j].ddl);
                //扣分数=之前的总费时+当前这科的完成时间-当前这科的完成时限
                //注意扣的分数不能为负数
                if(f[now]>f[pre]+score) //更新最小扣分数
                {
                    f[now]=f[pre]+score;
                    ans[now]=pre; //ans记录前驱(now状态由pre状态转化过来)
                }
            }
    cout<<f[(1<<n)-1]<<endl; //答案即为f[n科均完成的状态]
    
    int ed=(1<<n)-1;
    stack<string> stk;
    while(ed) //从最后的状态倒推至初始状态000
    {
        int x=0;
        int pre=ans[ed];
        for(int i=0;i<n;i++)
            if((ed>>i&1)&&!(pre>>i&1)) //如果该位改变(之前是0 现在是1)
            {
                x=i;
                break;
            }
        stk.push(a[x].lesson); 
        //因为ans记录的是更新转移过来的状态
        //所以
        ed=pre;
    }
    while(!stk.empty()) cout<<stk.top()<<endl,stk.pop();
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}

4550. 超级跳跳跳 - 最长上升子序列dp

4550. 超级跳跳跳 - AcWing题库

题目:

思路:

根据题目要求分析,就是求最长上升子序列的最大值

详见:【蓝桥杯集训26】线性DP(4 / 4)_Roye_ack的博客-CSDN博客

import java.util.*;

class Main
{
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        while(true)
        {
            int n=sc.nextInt();
            if(n==0) break;
            int[] f=new int[n+1],a=new int[n+1];
            for(int i=1;i<=n;i++) a[i]=sc.nextInt();
            
            int res=-1;
            for(int i=1;i<=n;i++)
            {
                f[i]=a[i];
                for(int j=1;j<i;j++)
                    if(a[j]<a[i]) f[i]=Math.max(f[i],f[j]+a[i]);
                res=Math.max(res,f[i]);
            }
            System.out.println(res);
        }
    }
}

4551. 猪猪存钱罐 - 完全背包问题

4551. 猪猪存钱罐 - AcWing题库 

题目:

已知钱币的总重量,和每种硬币单个重量及面额

求恰好凑出总重量的最小面额总值

若无法恰好凑出,输出This is impossible.

思路:

每种货币无限件 + 存钱罐重量有限制 = 完全背包模板

定义f[i]:总重量为i的最小总价值

套完全背包模板即可,注意初始化时f数组全为正无穷

且f[0]=0(重量为0的价值为0)

完全背包等各类背包问题【蓝桥杯集训25】背包DP(5 / 7)_Roye_ack的博客-CSDN博客

如果f[v]不是正无穷,说明刚好装满的状态可达,否则无法恰好装满

1、c++

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N=10010;
int f[N];

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int a,b;
        cin>>a>>b;
        int V=b-a;
        
        memset(f,0x3f,sizeof f);
        int n;
        cin>>n;
        f[0]=0;
        for(int i=1;i<=n;i++)
        {
            int w,v;
            cin>>w>>v;
            for(int j=v;j<=V;j++)
                f[j]=min(f[j],f[j-v]+w);
        }
        if(f[V]!=0x3f3f3f3f) cout<<"The minimum amount of money in the piggy-bank is "<<f[V]<<"."<<endl;
        else cout<<"This is impossible."<<endl;
    }
}

 2、java 这版vjudge格式被卡 acw可以过

import java.util.*;

class Main
{
    static int N=10010;
    static int[] f=new int[N];//f[i]总重量不超过i的最小总价值
    
    //每种物品无限件+有体积限制=完全背包问题
    public static void main(String[] args)
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        while(t-->0)
        {
            int a=sc.nextInt(),b=sc.nextInt();
            int V=b-a;
            
            int n=sc.nextInt(); 
            Arrays.fill(f,0x3f3f3f3f);
            
            f[0]=0; //重量为0的价值为0
            for(int i=1;i<=n;i++) 
            {
                int w=sc.nextInt(),v=sc.nextInt();
                
                for(int j=v;j<=V;j++)
                    f[j]=Math.min(f[j],f[j-v]+w);
            }

            if(f[V]!=0x3f3f3f3f) System.out.printf("The minimum amount of money in the piggy-bank is %d.\n",f[V]);
            else System.out.println("This is impossible.");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_61639349/article/details/129823659
4-6