算法进阶指南-动态规划-背包

1.数字组合
题目链接
在这里插入图片描述
题解:01背包方案数问题,直接套模板
java代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

public class Main {



    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n,m;

        n=sc.nextInt();
        m=sc.nextInt();
        int []a=new int[100+10];

        for(int i=1;i<=n;i++)
            a[i]=sc.nextInt();
        int dp[]=new int[10000+10];
        Arrays.fill(dp,0);
       
        dp[0]=1;//0的时候什么都不选 只有一种方法
        for(int i=1;i<=n;i++)
        {
            for(int j=m;j>=a[i];j--)
            {
                dp[j]+=dp[j-a[i]];//方法累加
            }
        }
        System.out.println(dp[m]);
    }




}

c++代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e2 + 7;
const int M = 1e4 + 7;
int dp[M], a[N];
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    dp[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = m; j >= a[i]; j--) {
            dp[j] += dp[j - a[i]];
        }
    }
    printf("%d\n", dp[m]);
    return 0;
}

2.自然数拆分Lunatic版
题目链接
在这里插入图片描述
题解:同上仍旧是方案数问题,只不过是完全背包

java代码:

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

public class Main {


    public static long Mod=2147483648L;
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n;
        n=sc.nextInt();

        long []dp=new long[4000+10];
        Arrays.fill(dp,0);
        dp[0]=1;
        for(int i=1;i<n;i++)
            for(int j=i;j<=n;j++)
                dp[j] = (dp[j] + dp[j - i ]) % Mod;

        System.out.println(dp[n]);

    }




}

c++代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 4005;
long long n, dp[N], a[N];
int main()
{
    cin >> n;
    dp[0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = i; j <= n; j++)
        dp[j] = (dp[j] + dp[j - i]) % 2147483648;
    cout << (dp[n] > 0 ? dp[n]-1 : 2147483648) << endl;
    return 0;
}


3.Jury Compromise
题目链接
在这里插入图片描述
题解:我们先不考虑|D-P|,就是让D+P最大,那么就是一个背包问题,因为背包每一个状态都是一个组合,我们只需要计算出每个组合此时的|D-P| ,也就是再背包原有的基础上再加一维记录此状态的|D-P|即可.
java代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public  class Main
{
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n,m;
        int dp[][][]=new int[850][250][30];
        int a[]=new int[210];
        int b[]=new int[210];

        int t=1;
        while(true){
            n=sc.nextInt();
            m=sc.nextInt();
            for(int i=0;i<=840;i++)
                for(int j=0;j<=230;j++)
                    Arrays.fill(dp[i][j],-9999);
            if(n==0&&m==0)
                break;
            for(int i=1;i<=n;i++){
                a[i]=sc.nextInt();
                b[i]=sc.nextInt();
            }

            dp[400][0][0]=0;
            for(int i=1;i<=n;i++)
                for(int j=0;j<=m;j++)//因为无法表示负数,我们把400当做0 
                    for(int k=0;k<810;k++){//类似01背包,多了一个考虑的因素
                        dp[k][i][j]=dp[k][i-1][j];
                        int now=a[i]-b[i];
                        if(k-now>800||k-now<0) continue;
                        if(j<1) continue;
                        dp[k][i][j]=Math.max(dp[k][i][j],dp[k-now][i-1][j-1]+a[i]+b[i]);

                    }

            	int base=400;
                    int v=0;
                    int res;
            while(dp[base+v][n][m]<0&&dp[base-v][n][m]<0) v++;//从最小的找起,直到找到状态存在的
            if(dp[base+v][n][m]>dp[base-v][n][m])  res=base+v;
            else res=base-v;
            int cnt=1;
            int ans[]=new int[100];
            while(m>0)//回事找方案
            {
                if(dp[res][n][m]==dp[res][n-1][m])n--;
                else
                {
                    ans[cnt++]=n;
                    if(res-(a[n]-b[n])>=0)
                    res-=(a[n]-b[n]);
                    n--;
                    m--;

                }
            }
            int sp = 0, sd = 0;
            for (int i = 0; i < cnt; i ++ )
            {
                sp += a[ans[i]];
                sd += b[ans[i]];
            }
            System.out.println("Jury #"+t++);
            System. out.println("Best jury has value "+sp+" for prosecution and value "+sd+" for defence:");
            for(int i=cnt-1;i>0;i--)
                System.out.printf(" "+ans[i]);
            System.out.println("\n");



        }

    }

}


c++代码:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 210, M = 810, base = 400;

int n, m;
int p[N], d[N];
int f[N][21][M];
int ans[N];

int main()
{
    int T = 1;
    while (scanf("%d%d", &n, &m), n || m)
    {
        for (int i = 1; i <= n; i ++ ) scanf("%d%d", &p[i], &d[i]);

        memset(f, -0x3f, sizeof f);
        f[0][0][base] = 0;

        for (int i = 1; i <= n; i ++ )
            for (int j = 0; j <= m; j ++ )
                for (int k = 0; k < M; k ++ )
                {
                    f[i][j][k] = f[i - 1][j][k];
                    int t = k - (p[i] - d[i]);
                    if (t < 0 || t >= M) continue;
                    if (j < 1) continue;
                    f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][t] + p[i] + d[i]);
                }

        int v = 0;
        while (f[n][m][base - v] < 0 && f[n][m][base + v] < 0) v ++ ;

        if (f[n][m][base - v] > f[n][m][base + v]) v = base - v;
        else v = base + v;

        int cnt = 0;
        int i = n, j = m, k = v;
        while (j)
        {
            if (f[i][j][k] == f[i - 1][j][k]) i -- ;
            else
            {
                ans[cnt ++ ] = i;
                k -= (p[i] - d[i]);
                i --, j -- ;
            }
        }

        int sp = 0, sd = 0;
        for (int i = 0; i < cnt; i ++ )
        {
            sp += p[ans[i]];
            sd += d[ans[i]];
        }

        printf("Jury #%d\n", T ++ );
        printf("Best jury has value %d for prosecution and value %d for defence:\n", sp, sd);

        sort(ans, ans + cnt);
        for (int i = 0; i < cnt; i ++ ) printf(" %d", ans[i]);
        puts("\n");
    }

    return 0;
}



4.Coins
题目链接
在这里插入图片描述
题解:完全背包裸题,没什么好说的

java代码:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

public class Main {



    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n,m;
        int a[]=new int[105];
        int c[]=new int[105];
        int f[]=new int[100000+10];
        int q[]=new int[100000+10];
        int g[]=new int[100000+10];


        while(true) {
            n = sc.nextInt();
            m = sc.nextInt();
            if (n == 0 && m == 0)
                break;
            for (int i = 1; i <= n; i++) {
                a[i] = sc.nextInt();

            }
            for (int i = 1; i <= n; i++) {
                c[i] = sc.nextInt();

            }
            Arrays.fill(f,0);
            Arrays.fill(q,0);
            f[0]=1;
            for(int i=1;i<=n;i++)
            {
                g=Arrays.copyOfRange(f,0,f.length-1);
                for(int j=0;j<a[i];j++)
                {      int hh=0,tt=-1;
                    for(int k=j;k<=m;k+=a[i])
                    {
                        f[k]=g[k];
                        if(hh<=tt && k-c[i]*a[i]>q[hh])
                        //如果当前窗口的内容超过了s个;
                        {
                            hh++;
                        }
                        if(hh<=tt)
                        {
                            f[k]=1;
                            //max(f[i-1][k],f[i-1][能转移里最大]+个数*v[i]);
                        }
                       
                        if(g[k]>0)
                        q[++tt]=k;
                    }
                }

            }
                        int ans=0;
            for(int i=1;i<=m;i++)
                if(f[i]>0) ans++;

            System.out.println(ans);

        }
    }

}

c++代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 105;
const int M = 1e5 + 10;
int a[N],c[N];
int f[M],used[M];


int main()
{
    ios::sync_with_stdio(false);

    int n,m;

    for ( ; ; )
    {
        int ans = 0;

        cin >> n >> m;
        if ( n == 0 && m == 0) break;

        for (int i = 1; i <= n; ++ i ) cin >> a[i];
        for (int i = 1; i <= n; ++ i ) cin >> c[i];

        memset(f,0,sizeof(f));
        memset(used,0,sizeof(used));

        f[0] = 1;

        for (int i = 1; i <= n; ++ i )
        {
            for (int j = 0; j <= m; ++ j ) used[j] = 0;
            for (int j = a[i]; j <= m; ++ j )
            {
                if (!f[j] && used[j - a[i]] < c[i] && f[j - a[i]])
                    f[j] = true, used[j] = used[j - a[i]] + 1;
            }
        }

        for (int i = 1; i <= m; ++ i )
            if (f[i]) ++ans;

        cout << ans << endl;
    }

    return 0;
}


有问题请留言或者私信,谢谢

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值