寒冰王座(记忆化搜索or01背包)

版权声明:转载请注明出处链接 https://blog.csdn.net/qq_43408238/article/details/88873088

不死族的巫妖王发工资拉,死亡骑士拿到一张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

这个题目我首先想到的还是递归,不知为何,我想也没想的就提交了,结果超时,唉,我总想碰一下运气,明知道会超时的。然后就考虑记忆化搜索,em,比上次写的时候顺畅了不少。

思路:递归+记忆化,有150,200,350的装备,每个东西都有买与不买两种情况,递归嘛,非常非常注重边界,还有就是开全局数组保存状态。剩下的在代码里注释了。

附加:我忽而发现也可以转化为01背包问题,我看很多的博客都是按完全背包问题(就是每件物品可以无限取)做的,就算是无限取,也要在背包容量还能装的时候吧,所以每一件物品可以变成可以装满背包的最小件件数。再套01背包的模板就可以了。

记忆化搜索代码:

 

#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include <algorithm>
#include <stdlib.h>
#include <cstdio>
#include<sstream>
#include<cctype>
#include <set>
#include<queue>
#include <map>
#include <iomanip>
#define  INF  0x3f3f3f3f
typedef long long ll;
ll ans[10010];//全局数组
using namespace std;
ll  solve(ll n);
ll MIN(ll a,ll b,ll c)
{
    return min(min(a,b),c);
}
int main()
{
    ll t,n,m;
    cin>>t;
    while(t--)
    {
        memset(ans,-1,sizeof(ans));
        cin>>n;
        cout<<solve(n)<<endl;
    }
}
ll  solve(ll n)
{
     if(n<0) return 200;//注意,这一句要放在最前面,第一:他小于150,但不能返回正常值,返回个大值,第二,此时ans[n]不一定等于-1
    if(n<150) return n;
    if(ans[n]!=-1) return ans[n];
      ans[n]=MIN(solve(n-150),solve(n-200),solve(n-350));
     return ans[n];

}

01背包代码:

#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include <algorithm>
#include <stdlib.h>
#include <cstdio>
#include<sstream>
#include<cctype>
#include <set>
#include<queue>
#include <map>
#include <iomanip>
typedef long long ll;
using namespace std;
const ll MAX=1000000;
ll vc[MAX];//价值与容量等价,让value与capacity 合为一个数组
ll dp[10000];
ll ans[]={0,150,200,350};
int main()
{
    ll t,n,m;
    scanf("%lld",&t);
    while(t--)
    {
        memset(vc,0,sizeof(vc));
        memset(dp,0,sizeof(dp));
        ll l=1;
       scanf("%lld",&n);
        for(ll i=1;i<=3;i++)
        {
            m=ceil(n*1.0/ans[i]);//转化:每一件转化为背包装不下的最小件数
            for(ll j=1;j<=m;j++)
            {
                vc[l++]=ans[i];
            }
        }
        for(ll i=1;i<l;i++)
        {
            for(ll j=n;j>=vc[i];j--)
            {
                dp[j]=max(dp[j],dp[j-vc[i]]+vc[i]);
            }
        }
        printf("%lld\n",n-dp[n]);

    }
}

猜你喜欢

转载自blog.csdn.net/qq_43408238/article/details/88873088