UVa:10306 e-Coins

灵感来自题下面那个图。

一开始想用dp[i][j]表示前i个coin得到j时的最少硬币数,但是后来想了想不满足无后效性。于是转化为dp[i][j][k]表示前i种硬币,分别得到x为j,y为k时的最少硬币数。这样答案就是dp[i][j][k],i==m,j*j+k*k==S*S的时候。这样对于每个coin,就那个图而言,枚举它每个终点,然后dp即可。一开始不知道哪写错了,还加了排序,一直没过样例,后来想了想发现数组的第一维没有必要写,排序也没必要写。然后就过了。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define MAXN 305
#define INF 2139062143
using namespace std;
int dp[MAXN][MAXN];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int m,S;
        scanf("%d%d",&m,&S);
        int x[45],y[45];
        memset(dp,0x7f,sizeof(dp));
        for(int i=0; i<m; ++i)
            scanf("%d%d",&x[i],&y[i]);
        dp[0][0]=0;
        for(int i=0; i<m; ++i)
        {
            for(int j=0; j<=S; ++j)
                for(int k=0; k<=S; ++k)
                    if(j>=x[i]&&k>=y[i])
                        dp[j][k]=min(dp[j][k],dp[j-x[i]][k-y[i]]+1);
        }
        int ans=INF;
        for(int i=0; i<=S; ++i)
            for(int j=0; j<=S; ++j)
                if(i*i+j*j==S*S&&dp[i][j])
                    ans=min(ans,dp[i][j]);
        if(ans!=INF)  printf("%d\n",ans);
        else  puts("not possible");
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值