一道清华大学计算机考研复试题,请教各位高手,谢谢!

zh822 2009-03-29 11:24:58
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。
如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
首先是要求凑成的邮票总值M,M<100
然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
输出:
能够凑成总值M的最少邮票张数。若无解,输出0。

样例输入:
10 5 1 3 3 3 4
样例输出:
3

用C语言进行编程,谢谢各位了!
...全文
696 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
jakqigle 2009-03-31
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 genius_tong 的回复:]
引用 2 楼 wuyu637 的回复:
用贪心算法就够了吧。


不行的吧,比如说,有这样几张票子:1分 1分 3分 3分 4分 4分 ,要凑成10分的总值,若用贪心,就是4+4+1+1,但正解是4+3+3,是不?
呵呵,不是很懂“贪心”具体的含义,但是同意一楼的看法,背包问题~
[/Quote]
貌似不可以出现重复的邮票面值。这个问题类似硬币问题,贪心。
小布 2009-03-31
  • 打赏
  • 举报
回复
顶2楼
zhoulehua 2009-03-31
  • 打赏
  • 举报
回复
楼上都是好样的。
scsnsjsl_cs_dn 2009-03-31
  • 打赏
  • 举报
回复
用数学的不等式求解?
zh822xa 2009-03-31
  • 打赏
  • 举报
回复
怎么加分呢?为什么我不能给你们分呢?
zh822xa 2009-03-31
  • 打赏
  • 举报
回复
谢谢各位了,受益匪浅,开始给分。。。
acdbxzyw 2009-03-30
  • 打赏
  • 举报
回复
这个确实不是贪心

动态规划找状态转移方程
这个比较难到我 现在基本还不熟
酝酿了挺久 写了个
看看吧

#include<stdio.h>

int main(void){
int M,N;
int temp,sum = 0,kindn;// 邮票面值的总和sum ,种类数kindnumber
int i,j,k;
int stamp[2][21]={0};//一行为邮票种类,二行为其数量
int value[101][21]={0};
//记录从1-M所需邮票的最少值和邮票数目

scanf("%d%d",&M,&N);
for(i=1,j=0;i<=N;i++){
scanf("%d",&temp);
sum += temp; //记录邮票总值
if(stamp[0][j] != temp){
++j;
stamp[0][j] = temp;
//记录各种邮票面值 后发现第一维无用,懒得改了
}
stamp[1][j] ++; // 记录temp面值邮票的数量
value[temp][0] = 1; //第0列记录所需邮票最少值
value[temp][j] = 1; //第temp列记录达到最少值需要的temp值邮票的数量
}
kindn = j; //邮票种类总数

if(sum < M){
printf("0\n");
return 1;
}
if(sum == M){
printf("%d\n",N);
return 1;
}
if(value[M][0] == 1){
printf("1\n");
return 1;
}

for(i=1;i<=M;i++){ //主循环,从1递增到M构成需要邮票的最少数
if(value[i][0] == 1) continue;
for(j=1;j<=i/2;j++){ //j 与 i-j 两两相加,取需邮票最少的一对更新数组
if(value[j][0] == 0 || value[i-j][0] == 0){
//有一个面值无法组合出来,则 value[i]无法组合出来
continue;
}
if(value[i][0] == 0
|| value[j][0]+value[i-j][0]<value[i][0]){
//初始化和寻找最小值
for(k=1;k<=kindn;k++){
if(value[j][k]+value[i-j][k] > stamp[1][k]){
break;
}
}
if(k > kindn){ //更新最小值
value[i][0] = value[j][0]+value[i-j][0];
for(k=1;k<=kindn;k++){
value[i][k] = value[j][k]+value[i-j][k];
}
}
}
}
}
printf("%d\n",value[M][0]);
//while(1) getchar();
return 1;
}
Paradin 2009-03-30
  • 打赏
  • 举报
回复
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。
如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
首先是要求凑成的邮票总值M,M <100
然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
输出:
能够凑成总值M的最少邮票张数。若无解,输出0。

样例输入:
10 5 1 3 3 3 4
样例输出:
3

解法:动态规划。


#include <stdio.h>
#define MAXN 20
#define MAXM 100
#define LARGE 1000

int main()
{
int total, n, i, j;
int face[MAXN];
int least[MAXM]; //least[k]表示凑成k元钱的最少硬币个数, 显然least[k] = min{least[k - face[i]] + 1}, 对i枚举.

scanf("%d%d", &total, &n);

for (i = 0; i < MAXM; ++i)
least[i] = LARGE; //初始化为无解

for (i = 0; i < n; ++i)
{
scanf("%d", &face[i]);
least[face[i]] = 1; //一张就可以
}

for (i = 0; i <= total; ++i)
{
int min = least[i];
for (j = 0; j < n; ++j)
{
if (i - face[j] >= 0 && least[i - face[j]] + 1 < min)
min = least[i - face[j]] + 1;
}
least[i] = min;
}

printf("%d\n", least[total]);
return 0;
}
wjb_yd 2009-03-30
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 genius_tong 的回复:]
引用 2 楼 wuyu637 的回复:
用贪心算法就够了吧。


不行的吧,比如说,有这样几张票子:1分  1分    3分  3分  4分  4分  ,要凑成10分的总值,若用贪心,就是4+4+1+1,但正解是4+3+3,是不?
呵呵,不是很懂“贪心”具体的含义,但是同意一楼的看法,背包问题~
[/Quote]

恩呢,贪心是不行的,甚至有可能到最后凑不出10了
wjb_yd 2009-03-30
  • 打赏
  • 举报
回复
M<100,N<20,就可以用动态规划了,楼主到网上查查0-1背包问题的解释就可以了

如果m,n没有限制的话,只能用搜索了
acdbxzyw 2009-03-29
  • 打赏
  • 举报
回复
最基本的搜索问题
贪心的背包问题。比动态规划的背包问题简单多了。
genius_tong 2009-03-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wuyu637 的回复:]
用贪心算法就够了吧。
[/Quote]

不行的吧,比如说,有这样几张票子:1分 1分 3分 3分 4分 4分 ,要凑成10分的总值,若用贪心,就是4+4+1+1,但正解是4+3+3,是不?
呵呵,不是很懂“贪心”具体的含义,但是同意一楼的看法,背包问题~
wuyu637 2009-03-29
  • 打赏
  • 举报
回复
用贪心算法就够了吧。
  • 打赏
  • 举报
回复
典型背包算法

假设想要背包精确地承重20磅,并且有5个可以选择放入的数据项,它们的重量
* 依次为11磅、8磅、7磅、6磅和5磅。对于选择放入的数据项数量不大时,人类很善于通过观察
* 就可以解决这个问题。于是大概可以计算出只有8磅、7磅和5磅的数据项加在一起和为20磅。
* 如果想要计算机来解决这个问题,就需要给计算机更详细的指令。算法如下:
* 1.如果在这个过程中的任何时刻,选择的数据项的总和符合目标重量,工作就完成了。
* 2.从选择第一个数据项开始。剩余的数据项的加和必须符合背包的目标重量减去第一个数据
* 项的重量;这是一个新的目标重量。
* 3.逐个地试每种剩余数据顶组合的可能性。但是,注意并不需要去试所有的组合,因为只要
* 数据顶朗和大于目标重量的时候,就停止添加数据项。
* 4.如果设有组合合适的话,放弃第—‘个数据项,并且从第二个数据项开始再重复一边整个
* 过程。
* 5.继续从第三个数据项开始,如此下去直到你已经试过所有的组合,这时知道没有解决答案
* 。
* 在刚刚描述的这个例子中,从11开始。现在想要剩余的数据项和为9(20减去u)。对于9,
* 从很小的8开始。现在想要剩余的数据项和为1(9减去8)。从7开始,但是它大于L,于是尝
* 试6,然后试5*它们都太大了d现在已经试过了所有的数据项,所以知道包含8的任何组合
* 和都不可能为9。接着尝试7,于是现在开始找的目标为2(9减去7)。


http://www.cnblogs.com/renmin/archive/2008/04/08/1142754.html
看看这个吧,基本一样。
ysysbaobei 2009-03-29
  • 打赏
  • 举报
回复
zh822 2009-03-29
  • 打赏
  • 举报
回复
谢谢各位了,能不能给出一些代码呢,非常感谢!

65,211

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧