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;
    }
  • 相关阅读:
    Codeforces Round #443 (Div. 2)ABC
    Codeforces Round #442 (Div. 2) ABC
    Wannafly挑战赛2 Cut
    热爱工作的蒜蒜
    Codeforces Round #441 (Div. 2) (ABC)
    Codeforces Round #440 (Div. 2)(ABC)
    Codeforces Round #439 (Div. 2)(ABC)
    sphinx 分词搭建手册
    [转]Chrome 控制台console的用法
    shell脚本复制文件夹内容到另外的文件夹,如果存在则自动备份
  • 原文地址:https://www.cnblogs.com/wmxl/p/4747273.html
Copyright © 2011-2022 走看看