zoukankan      html  css  js  c++  java
  • HDU 1248 寒冰王座 (水题的N种做法!)(含完全背包)

    寒冰王座

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 13177    Accepted Submission(s): 6718


    Problem Description
    不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.

    死亡骑士:"我要买道具!"

    地精商人:"我们这里有三种道具,血瓶150块一个,魔法药200块一个,无敌药水350块一个."

    死亡骑士:"好的,给我一个血瓶."

    说完他掏出那张N元的大钞递给地精商人.

    地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿."

    死亡骑士:"......"

    死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.

    现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费.
     
    Input
    输入数据的第一行是一个整数T(1<=T<=100),代表测试数据的数量.然后是T行测试数据,每个测试数据只包含一个正整数N(1<=N<=10000),N代表死亡骑士手中钞票的面值.

    注意:地精商店只有题中描述的三种道具.
     
    Output
    对于每组测试数据,请你输出死亡骑士最少要浪费多少钱给地精商人作为小费.
     
    Sample Input
    2 900 250
     
    Sample Output
    0 50
     
    Author
    Ignatius.L
     
    Recommend
    Ignatius.L   |   We have carefully selected several similar problems for you:  1171 1114 1284 2191 2159
     
    本来是学习完全背包的,看到了这一题,这题可以说是很裸的完全背包。但是它有一点特殊就是它的每个物品的花费(重量)和它的价值是一样的,所以状态转移方程:f[j]=max(f[j],f[j-w[i]]+w[i]); 也正是因为这个特殊性,使它不仅仅可以用背包,还可以很多其他方法!
    首先是完全背包
    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 12345
    #define M 12
    
    int n;
    int w[4]={0,150,200,350};
    int f[N];
    int main()
    {
        int T;cin>>T;
        while(T--)
        {
            scanf("%d",&n);
            for(int i=1;i<=3;i++)
                for(int j=w[i];j<=n;j++)
            {
                f[j]=max(f[j],f[j-w[i]]+w[i]);
            }
            cout<<n-f[n]<<endl;
        }
        return 0;
    }
    

    一种非常直接暴力的做法

    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 12345
    #define M 12
    
    int n;
    int main()
    {
        int T;cin>>T;
        while(T--)
        {
            int ma=0;
            scanf("%d",&n);
            for(int i=0;i<=n/150;i++)
                for(int j=0;j<=n/200;j++)
                    for(int k=0;k<=n/350;k++)
                    {
                        int sum=150*i+200*j+350*k;
                        if(sum<=n)
                            ma=max(ma,sum);
                    }
            cout<<n-ma<<endl;
        }
        return 0;
    }

    仔细看题可以发现,无敌药水的价钱正好等于血瓶+魔法药品的价钱,所以无敌药品可以直接忽略了,因此可以把上面的代码稍微优化一下,3重循环变成2重了:

    for(int i=0;i<=n/150;i++)
                for(int j=0;j<=n/200;j++)
                    {
                        int sum=150*i+200*j;
                        if(sum<=n)
                            ma=max(ma,sum);
                    }

    仔细看一下两种药品价钱150,200,对于小于150的数直接就是那个数,大于300的都不会超过50,所以大于三百直接%50。在这之间的如果判断%200和%150哪个小,哪个小取哪个。这个复杂度就非常低了,是常数级的。

    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 12345
    #define M 12
    
    int n;
    int main()
    {
        int T;cin>>T;
        while(T--)
        {
            scanf("%d",&n);
            if(n>=150)
            {
                if(n>=300)
                    n=n%50;
                else
                    if(n%200<n%150)
                        n=n%200;
                    else
                        n=n%150;
            }
            cout<<n<<endl;
        }
        return 0;
    }

    其实这题用搜索也可以做,bfs

    #include<queue>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 12345
    #define M 12
    
    int n;
    int vis[N];
    int bfs()
    {
        memset(vis,0,sizeof(vis));
        int temp=n;
        queue<int>q;
        q.push(temp);
        while(!q.empty())
        {
            temp=q.front();
            q.pop();
            if(!vis[temp-150] && temp-150>=0)
            {
                vis[temp-150]=1;
                q.push(temp-150);
            }
            if(!vis[temp-200] && temp-200>=0)
            {
                vis[temp-200]=1;
                q.push(temp-200);
            }
        }
        return temp;
    }
    int main()
    {
        int T;cin>>T;
        while(T--)
        {
            int ma=0;
            scanf("%d",&n);
            cout<<bfs()<<endl;
        }
        return 0;
    }
  • 相关阅读:
    cf C. Vasya and Robot
    zoj 3805 Machine
    cf B. Vasya and Public Transport
    cf D. Queue
    cf C. Find Maximum
    cf B. Two Heaps
    cf C. Jeff and Rounding
    cf B. Jeff and Periods
    cf A. Jeff and Digits
    I Think I Need a Houseboat
  • 原文地址:https://www.cnblogs.com/wmxl/p/4747273.html
Copyright © 2011-2022 走看看