山东理工Greatest Number 解题报告

题目描述:地址: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;
}



你可能感兴趣的:(山东理工Greatest Number 解题报告)