题目描述:地址:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2157
题目自己看,很简单的游戏,从n个数中取不超过四个的数,使得这几个数的和最接近给定的数m
这道题属于简单提,网上也有分析,我主要提醒一下几点:
1.一定要注意是不超过四个数,那么就可以是一个.....到四个
2.纯暴力会超时,暴力+技巧才会AC
怎么才算是有技巧呢?我的做法是这样的,将待挑选的数及任意两个数的和存贮到一个数组里面,然后对每一个sum[i]数用二分查找法
查找另一个符合要求的数sum[j]使得sum[i]+sum[j]<m而且比曾经出现过的最大数大,那么就更新结果值.
需要注意的是,以为数组里面存贮的是一个数和任意两个数字的和,那么组合情况只有三种: 两个数,三个数,四个数,没有一个数(自己好好想一下为什么)
那么我们就需要判断有时候取一个数也可能满足要求的情况,那么我们可以在输入的时候判断符合要求的数,并暂时存贮到结果变量中取
后来,路东方同学提醒我说,可以让第一个数为0 ,那么,就可以出现所有的组合了,而且也不会漏掉情况了,我恍然大悟,明白了.有兴趣的同学可以自己修改一下,
我下面的程序与并没有用他的做法,稍微麻烦了一下,多了一个判断语句
下面给出源代码:
#include <stdio.h> #include <algorithm> #include <iostream> using namespace std; int sum[5555555]; int main() { int n,m,ca=1; while(scanf("%d%d",&n,&m)&&(n||m)) { printf("Case %d: ",ca++); int i,j,aim=0; for(i=0;i<n;i++) //输入数据 { scanf("%d",&sum[i]); if(sum[i]<=m&&sum[i]>=aim) //判断这个数据是否符合要求 aim=sum[i]; } int len=n; for(i=0;i<n;i++) for(j=0;j<n;j++) sum[len++]=sum[i]+sum[j]; //求任意两个数的和 sort(sum,sum+len); for(i=0;i<len;i++) { int l=0,h=len,mi; while(l<h) //对当前的数用二分查找法查找另一个满足要求的数 { mi=(l+h)/2; if(sum[mi]+sum[i]<=m) { if(sum[i]+sum[mi]>=aim) aim=sum[i]+sum[mi]; l=mi+1; } else h=mi; } } printf("%d\n\n",aim); } return 0; }