凑数字游戏

来源:互联网 发布:黄宏怎么了知乎 编辑:程序博客网 时间:2024/05/11 19:09
Problem Description
金牌大图神的算法能力最近又有不少提高~
为了杭电ACM集训队的可持续性发展,现在他帮忙出了一道题目来训练新队员——
给出4种数字583,1643,3233,5989,依次分别有n,m,k,g个,请找出用这些数字能凑成的和最接近L的数,如果有2个同样接近的,请输出较大的那个。
 


Input
输入数据第一行是数据的组数T(1 <= T <= 70);
每组数据的第一行是4个正整数n,m,k,g(n,m,k,g<= 100);
每组数据的第二行是1个正整数L(L<=1200000);
以上数据的含义详见题目描述。
 


Output
对于每组数据,输出一个最接近L的数字,每组数据输出一行。
 


Sample Input
2
1 2 3 4
3286
1 2 2 2
3870
 


Sample Output
3286

3869


我的理解:拿到这个题目的第一反应是装箱问题。于是就想用01背包的思想解决问题。可惜超时了。

后来看到给我们的n,m,k,g都很小,所以枚举了所有的可能情况。AC

代码如下:运用二分的方法加快寻找速度。由于这个题目hdu没有挂到外面,比赛结束又没有把账号拿出来,所有这个代码是凭着我的记忆写的。仅供参考

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;#define maxn 1200009bool vis[maxn];int dp[maxn];int main(){    int T,L,i,j,t,ans1,ans2,ans;    int a[5];    int b[5]= {583,1643,3233,5989};    scanf("%d",&T);    while(T--)    {        for(i=0; i<4; i++)            scanf("%d",&a[i]);        scanf("%d",&L);        memset(vis,0,sizeof(vis));        int num=1,tem=1;        dp[0]=0;        vis[0]=1;        for(i=0; i<4; i++)        {            tem=num;            for(j=1; j<=a[i]; j++)            {                for(t=0; t<num; t++)                {                    if(vis[dp[t]+j*b[i]]==0)                        dp[tem++]=dp[t]+j*b[i];                    vis[dp[t]+j*b[i]]=1;                }            }            num=tem;        }        sort(dp,dp+num);        dp[num]=2*maxn;        int l=0,r=num,mid,ret;        while(l<=r)        {            mid=(l+r)>>1;            if(dp[mid]>=L)r=mid-1,ret=dp[mid];            else l=mid+1;        }        ans1=ret;        l=0,r=num;        while(l<=r)        {            mid=(l+r)>>1;            if(dp[mid]<=L)l=mid+1,ret=dp[mid];            else r=mid-1;        }        ans2=ret;        if(ans1-L<=L-ans2)ans=ans1;        else ans=ans2;        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击