HDOJ 2546 饭卡 解题报告

    很有趣的一道题。简单分析一下可知:

    (1)如果所有的菜的总金额sum小于等于卡上金额value-5,我们可以购买所有的菜,并且最终余额是value-sum。

    (2)如果所有的菜,除去最贵的菜,的金额sum-max小于等于value-5,我们可以先购买其他的菜,最终卡上金额必大于等于5,最后购买那道最贵的菜,使总金额最低,并且最终余额也是是value-sum,可与(1)条件合并。

    (3)如果卡上金额小于5,啥也买不了,直接输出吧。

    (4)如果都不符合,那就进入最复杂的处理了。先购买适量的菜,使卡内余额的金额大于等于且最接近5,最后购买最贵的菜就好了。子问题也就是01背包问题。

    额,还是看代码吧。

#include <iostream>

using namespace std;



const int MAX=1010;

int dp[MAX];

int v[MAX];



int main()

{

    int i,j,n,max,sum,pos,money,temp;

    while(cin>>n && n)

    {

        for(sum=max=i=0;i<n;i++)

        {

            cin>>v[i];

            sum+=v[i];

            if(max<v[i])

                max=v[pos=i];

        }

        cin>>money;

        if(money<5)

            cout<<money<<endl;

        else if(sum-max<=money-5)

            cout<<money-sum<<endl;

        else

        {

            memset(dp,0,sizeof(dp));

            if(pos!=n-1)

            {

                temp=v[pos];

                v[pos]=v[n-1];

                v[n-1]=temp;

            } //仅交换最大值到最后一位,比排序快吧

            for(i=0;i<n-1;i++)

                for(j=money-5;j>=v[i];j--)

                    dp[j]=dp[j]>dp[j-v[i]]+v[i]?dp[j]:dp[j-v[i]]+v[i]; //01背包问题

            cout<<money-dp[money-5]-max<<endl;

        }

    }

}

    额,自我感觉代码过是过了,不够完美。网上搜到的一份代码如下:

#include<stdio.h>

#include<algorithm>

using namespace std;

int a[1050],dp[1050];



int main()

{

    int n,m,max,i,j;

    while(scanf("%d",&n),n)

    {

        for(i=0;i<n;i++)

            scanf("%d",&a[i]);

        sort(a,a+n);

        scanf("%d",&m);

        memset(dp,0,sizeof(dp));

        dp[0]=1;

        max=0;

        for(i=0;i<n;i++)

            for(j=m-5;j>=0;j--)

                if(dp[j])

                {

                    dp[j+a[i]]=1;

                    if(j+a[i]>max)

                        max=j+a[i];

                }

            printf("%d\n",m-max);

    }

    return 0;

}

    他的动态规划写的比我漂亮,但是不是所有情况都要这样处理。测试中两份代码都AC,时间都是15MS。

    结合两份代码,可以写出来更好的代码了。。。第二份代码中dp数组只有标记功能,可以不用int类型,char就够了。如果想更省一点,char可以分成8份用。。。

    做ACM的人可能都有这样的思想,极致节约的时间,空间和代码量。这也是我追求的美学。

    没事又综合了一下,如下代码,亦AC了:

#include <iostream>

#include <algorithm>

using namespace std;



const int MAX=1010;

char dp[MAX];

int v[MAX];



int main()

{

    int i,j,n,max,sum,pos,money,temp;

    while(cin>>n && n)

    {

        for(sum=max=i=0;i<n;i++)

        {

            cin>>v[i];

            sum+=v[i];

            if(max<v[i])

                max=v[pos=i];

        }

        cin>>money;

        if(money<5)

            cout<<money<<endl;

        else if(sum-max<=money-5)

            cout<<money-sum<<endl;

        else

        {

            memset(dp,0,sizeof(dp));

            dp[0]=1;

            if(pos!=n-1)

            {

                temp=v[pos];

                v[pos]=v[n-1];

                v[n-1]=temp;

            }

            for(i=0;i<n;i++)

                for(j=money-5;j>=0;j--)

                    if(dp[j])

                    {

                        if(max<j+v[i])

                        {

                            max=j+v[i];

                            if(i==n-1)

                                break;

                        }

                        dp[j+v[i]]=1;

                    }

            cout<<money-max<<endl;

        }

    }

}

 

你可能感兴趣的:(OJ)