动态规划简单题(-背包问题)

NYOJ-289-苹果

苹果
时间限制:3000 ms | 内存限制:65535 KB
难度:3
描述
ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。

输入
有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n、v同时为0时结束测试,此时不输出。接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w。所有输入数字的范围大于等于0,小于等于1000。
输出
对每组测试数据输出一个整数,代表能放入背包的苹果的总价值。
样例输入

3 3
1 1
2 1
3 1
0 0

样例输出

2

由题不难得到这道题是01背包问题(不装满、有限)
代码:

#include <stdio.h> 
#include <string.h>
//#include <algorithm>
//using namespace std;//效率低
#define max(a,b) a>b?a:b
int main()
{
    int n,v,i,j;
    while(~scanf("%d%d",&n,&v),n,v)
    {
/*      int c[1010],w[1010],sum[1010];
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&c[i],&w[i]);
        } 
        memset(sum,0,sizeof(sum));
        for(i=0;i<n;i++)
        {
            for(j=v;j>=c[i];j--)//j<c[i]说明背包不够放 
            {
                sum[j]=max(sum[j],sum[j-c[i]]+w[i]);// 比较放这个和不放这个的大小 
            }
        }*///提高效率 
        int c,w,sum[1010];
        memset(sum,0,sizeof(sum));
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&c,&w);
            for(j=v;j>=c;j--)//j<c[i]说明背包不够放 
            {
                sum[j]=max(sum[j],sum[j-c]+w);// 比较放这个和不放这个的大小 
            }
        }
        printf("%d\n",sum[v]);
    }
    return 0;
} 

NYOJ-311-完全背包

时间限制:3000 ms | 内存限制:65535 KB
难度:4
描述
直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是c,价值是w。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。本题要求是背包恰好装满背包时,求出最大价值总和是多少。如果不能恰好装满背包,输出NO

输入
第一行: N 表示有多少组测试数据(N<7)。
接下来每组测试数据的第一行有两个整数M,V。 M表示物品种类的数目,V表示背包的总容量。(0< M<=2000,0< V<=50000)
接下来的M行每行有两个整数c,w分别表示每种物品的重量和价值(0< c<100000,0< w<100000)
输出
对应每组测试数据输出结果(如果能恰好装满背包,输出装满背包时背包内物品的最大价值总和。 如果不能恰好装满背包,输出NO)
样例输入

2
1 5
2 2
2 5
2 2
5 1

样例输出

NO
1

AC

#include <stdio.h>
#include <string.h>
#define max(a,b) a>b?a:b
int dp[100010];
int main()
{
    int n,m,v;//m数目,v背包容量 
    scanf("%d",&n);
    while(n--)
    {
        int c,w;
        int i,j;
        memset(dp,-0x3f,sizeof(dp));
        dp[0]=0;
        scanf("%d%d",&m,&v);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&c,&w);
            for(j=c;j<=v;j++)
            {
                dp[j]=max(dp[j],dp[j-c]+w);
            }
        } 
        if(dp[v]<0)//这里要判断的是dp[背包总容积] 
            printf("NO\n");
        else
            printf("%d\n",dp[v]);
    }
    return 0;
} 

采药

题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 如果你是辰辰,你能完成这个任务吗?

输入
第一行有两个整数T(1 < = T < = 1000)和M(1 < = M < = 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出
输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例输入

70 3
71 100
69 1
1 2

样例输出

3

提示

对于30%的数据,M < = 10;对于全部的数据,M < = 100。

代码

#include <stdio.h>
#include <string.h>
#define max(a,b) a>b?a:b
int main()
{
    int st,m;
    scanf("%d%d",&st,&m);
    int i,j,t,value;
    int dp[1005]={0};
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&t,&value);
        for(j=st;j>=t;j--)
        {
            dp[j]=max(dp[j],dp[j-t]+value);
        }
    }
    printf("%d\n",dp[st]);
    return 0;
}

1149: 多重部分和问题

时间限制: 1 Sec 内存限制: 128 MB
提交: 160 解决: 88

题目描述
有n中不同大小的数字ai,每种各mi个。判断是否可以从这些数字之中选出若干使他们的大小恰好为K.
限制条件

1<=n<=100
1<=ai,mi<=100000
1<=k<=100000

输入
多组数据。
第一行n。第二行不同的数字ai.第三行对应数字拥有的个数

输出
能挑选若干恰好和为K则输出“Yes”,反之输出“No”.

样例输入

1
3
3 5 8
3 2 2
17

样例输出

Yes

可以这样想:把mi个数字ai拆开,当做01背包问题来做就简单了很多
代码:

#include <stdio.h>
#include <string.h>
#define max(a,b) a>b?a:b
int a[100005],m[100005],dp[100005];
int main()
{
    int t,n,k,i,j;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,-0x3f,sizeof(dp));
        dp[0]=0;//初始化
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(i=1;i<=n;i++) 
            scanf("%d",&m[i]);
        scanf("%d",&k);//输入
        for(i=1;i<=n;i++)
        {
            while(m[i]--)//m[i]是a[i]的个数
            {
                for(j=k;j>=a[i];j--)
                {
                    dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
                }
            }
            if(dp[k]==k)//如果相加得到k就退出 输出yes
            {
                printf("Yes\n");
                break;
            }
        } 
        if(dp[k]<0)
            printf("No\n");
    }
    return 0;
} 

HDU-1712-ACboy needs your help

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6346 Accepted Submission(s): 3504

Problem Description
ACboy has N courses this term, and he plans to spend at most M days on study.Of course,the profit he will gain from different course depending on the days he spend on it.How to arrange the M days for the N courses to maximize the profit?

Input
The input consists of multiple data sets. A data set starts with a line containing two positive integers N and M, N is the number of courses, M is the days ACboy has.
Next follow a matrix A[i][j], (1<=i<=N<=100,1<=j<=M<=100).A[i][j] indicates if ACboy spend j days on ith course he will get profit of value A[i][j].
N = 0 and M = 0 ends the input.

Output
For each data set, your program should output a line which contains the number of the max profit ACboy will gain.

Sample Input

2 2
1 2
1 3
2 2
2 1
2 1
2 3
3 2 1
3 2 1
0 0

Sample Output

3
4
6

题意:
一个学生用M天的时间复习N门课程,每门课程花费不同的天数,有不同的收获。问如何安排这M天,使得收获最大。
思路:
可以将每一门课看成一个分组,每门课不同天数的选择看成是分组的物品(显然只能有一个选择),
物品的费用即为花费的天数,物品的价值为题中给出的收获。该题中背包容量最大为M。
设dp[x]为前i组物品,在背包容量为x(即费用为x)时的最大价值。则将i从1到N进行过历遍后(第一重循环),dp[m]即为所求。

AC

#include <stdio.h>
#include <string.h>
#define max(a,b) a>b?a:b
int dp[105];
int main()
{
    int n,m;
    int i,j,k,q;
    int a[105][105];
    while(scanf("%d%d",&n,&m),n,m)// n节课,m是有的天数 
    {
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)//课程 
        {
            for(j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);//a[i][j] i课花费j天的收获 
            }
            for(k=m;k>=1;k--)//倒着放 
            {
                for(q=1;q<=k;q++){//q<=k最多不能多于给的最多天数 
                    dp[k]=max(dp[k],dp[k-q]+a[i][q]);
                }   
            } 
        } 
        printf("%d\n",dp[m]);
    } 
    return 0;
} 

HDU-2191-悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

##
Problem Description
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

后记:
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——
感谢父母,他们给予我们生命,抚养我们成人;
感谢老师,他们授给我们知识,教我们做人
感谢朋友,他们让我们感受到世界的温暖;
感谢对手,他们令我们不断进取、努力。
同样,我们也要感谢痛苦与艰辛带给我们的财富~

Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。

Sample Input

1
8 2
2 100 4
4 100 2

Sample Output

400

题意:
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?
Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,
然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。

AC:

#include <stdio.h>
#include <string.h>
#define max(a,b) a>b?a:b
int main()
{
    int t,n,m;
    int i,j;
    int dp[105];
    scanf("%d",&t);
    while(t--)
    {
        int p,h,c;//p每袋价值,h每袋重量,c袋数 
        scanf("%d%d",&n,&m);//n元,m种 
        memset(dp,0,sizeof(dp));//初始化放for外面 
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p,&h,&c);
            while(c--)
            {
                for(j=n;j>=p;j--)
                {
                    dp[j]=max(dp[j],dp[j-p]+h);
                } 
            } 
        } 
        printf("%d\n",dp[n]);
    } 
    return 0;
}

收获:这类题可以通过观察提议判断题目中要求 物品无限、有限、背包装满、不装满,然后根据这些条件来做题。
其中物品无限:

for(i=1;i<=n;i++)
{
    for(j=a[i];j<sweight/*总重*/;j++)//正着放
        dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}

物品有限:

for(i=1;i<=n;i++)
{
    for(j=sweight/*总重*/;j>=a[i];j--)//倒着放
        dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}

装满:
初始化:

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

不装满:

memset(dp,0,sizeof(dp));

以上。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值