【滚动背包】hdoj 2546饭卡

饭卡

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 37289    Accepted Submission(s): 12803

Problem Description

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。

Input

多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。

Output

对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。

Sample Input

1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0

Sample Output

-45 32

Source

UESTC 6th Programming Contest Online

V1【错误】 TLE快排太慢

1

#include <stdio.h>
#include <stdlib.h>
void sot(int a[],int l,int r)
{
    int i=l,j=r,k=a[i];
    if(i>=j)return ;
    while(i<j)
    {
        while(i<j&&k<=a[j])j--;
        a[i]=a[j];
        while(i<j&&a[i]<=k)i++;
        a[j]=a[i];
        a[i]=k;
        sot(a,l,i-1);
        sot(a,i+1,r);
    }
}
int main()
{
    int n,i,m,v[1005],dp[1100],j;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        for(i=1; i<=n; i++)
            scanf("%d",&v[i]);
            sot(v,1,n);
        scanf("%d",&m);
        for(i=0;i<1100;i++)
            dp[i]=m;
        for(i=1; i<n; i++)
        {
            for(j=m; j>=5; j--)
            {
                if(j-v[i]>=5)
                    dp[j]=dp[j]<dp[j-v[i]]-v[i]?dp[j]:dp[j-v[i]]-v[i];
                else
                    dp[j]=dp[j];
            }
        }
        if(m<5)
            printf("%d\n",m);
        else
        printf("%d\n",dp[m]-v[n]);
    }
    return 0;
}

V2【正确】(就是把V1改成用c++ stl sort排序做)
从网上查了一下,sort函数用的introsort算法:
1. 快排
2. 递归深度过深时切成堆排

3. partition小于一定阈值时切成插入排序

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
    int n,i,m,a[1005],dp[1005],j;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        for(i=1; i<=n; i++)
            scanf("%d",&a[i]);
            sort(a+1,a+n+1);
        scanf("%d",&m);
        for(i=0;i<=1003;i++)
            dp[i]=m;
        for(i=1; i<n; i++)//这里一开始我写成了i<=n,把最大的算进去了肯定就错了
        {
            for(j=m; j>=5; j--)
                if(j-a[i]>=5)
                    dp[j]=min(dp[j-a[i]]-a[i],dp[j]);
        }
        if(m<5)
            printf("%d\n",m);
        else
        printf("%d\n",dp[m]-a[n]);//最大的直接在这里剪掉
    }
}
//这里一开始我写成了i<=n,把最大的算进去了肯定就错了
        {
            for(j=m; j>=5; j--)
                if(j-a[i]>=5)
                    dp[j]=min(dp[j-a[i]]-a[i],dp[j]);
        }
        if(m<5)
            printf("%d\n",m);
        else
        printf("%d\n",dp[m]-a[n]);//最大的直接在这里剪掉
    }
}

V3【正确】

用c怎么了QAQ,c也是可以的!因为排序不是必须的,我们要的只是最大值,于是

#include <stdio.h>
#include <stdlib.h>
int min(int a,int b)
{
    if(a>b)return b;
    else return a;
}
int main()
{
    int n,i,dp[1005],a[1005],m,j,max,remax;
    while(scanf("%d",&n)!=EOF&&n)
    {
        max=0;//一开始没置零,wa了好几回儿
        for(i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>max)
            {
                max=a[i];
                remax=i;
            }
        }
        scanf("%d",&m);
        if(m<5)printf("%d\n",m);//这个位置比较好
        else
        {
            for(i=0; i<=1003; i++)
                dp[i]=m;
            for(i=1; i<=n; i++)
            {
                if(i!=remax)
                {
                    for(j=m; j>=5; j--)
                        if(j-a[i]>=5)
                            dp[j]=min(dp[j-a[i]]-a[i],dp[j]);
                }
            }
            printf("%d\n",dp[m]-max);
        }
    }
    return 0;
}

一开始wa的时候很懵 然后敲了顺序的,也算是巩固一下,就是V4版本了。顺便贴出来

V4【正确】

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int maxx(int a,int b)
{
    if(a<b)return b;
    else return a;
}
int main()
{
    int n,i,dp[1005],a[1005],m,j,max,remax;
    while(scanf("%d",&n)!=EOF&&n)
    {
        max=0;
        for(i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>max)
            {
                max=a[i];
                remax=i;
            }
        }
        scanf("%d",&m);
        memset(dp,0,sizeof(dp));
        if(m<5)printf("%d\n",m);
        else
        {
            for(i=1; i<=n; i++)
            {
                for(j=m; j>=0; j--)
                {
                    if(i!=remax&&j>=a[i])
                        dp[j]=maxx(dp[j],dp[j-a[i]]+a[i]);
                }
            }
            printf("%d\n",m-dp[m-5]-max);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/flyf000/article/details/79391686
今日推荐