TYVJ1199

这题切了,顿时感觉很爽,这题彻底摆脱别人的思路和代码,完全是自己想自己写的,本来以为可能会超时,但是想不到别的方法就想把自己的思路写出来验证一下对不对,后来经过无数次的修改调试,最后A了,当时就算是返回TLE也不会感觉有什么,没想到竟然A了,oh yeah~
这题还是验证性的dp
dp[0][i][j]表示前i种能否表示j
dp[1][i][j]表示前i种表示j需要的最小邮票张数
最后目标值dp[0][m][j]
(mmax表示能表示的最大的值)
这一题比积木城堡那题多了两个很恶心的条件,最多n张,每种
有无限张
枚举第i种邮票
枚举每种邮票的使用次数j(j<=n &&j*a[i]<=mmax)
枚举k:从j*a[i]->mmax
如果前i-1种能表示k-j*a[i]并且其所使用的最小张数+j<=n
{
更新dp[0][i][k] = dp[0][i][k-j*a[i]] = 1;
更新dp[1][i][k] = min(dp[1][i][k],dp[0][i-1][k-j*a[i]]+j);
更新dp[1][i][k-j*a[i]] = min(dp[1][i][k-j*a[i]],dp[1][i-1][k-j*a[i]]);
}
最后枚举0->mmax
当dp[0][m][i]=false 时
i-1就是answer

 

 

#include<cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 11111111
using namespace std;
const int maxv = 25600;
const int maxn = 105;
int dp[2][maxn][maxv],a[maxn];
int main()
{
   // freopen("in.txt","r",stdin);
    int n,m;
    cin>>n>>m;
    int mmax = -1;
    for(int i = 1;i<=m;++i)
    {
        scanf("%d",&a[i]);
        mmax = max(mmax,a[i]);
    }
    mmax*=n;
    sort(a+1,a+1+m);
    memset(dp,0,sizeof(dp));
    for(int i = 0;i<=m;++i)
        dp[0][i][0] = 1;
    for(int i = 1;i<=m;++i)
        for(int j = 1;j<=mmax;++j)
            dp[1][i][j] = INF;
    for(int i = 1;i<=m;++i)
        for(int j = 1;j<=n && j*a[i]<=mmax;j++)
        {
            for(int k = mmax;k>=j*a[i];--k)
            {
                if(dp[0][i-1][k-j*a[i]] && dp[1][i-1][k-j*a[i]]+j<=n)
                {
                    dp[0][i][k] = dp[0][i][k-j*a[i]] = 1;
                    dp[1][i][k] = min(dp[1][i][k],dp[1][i-1][k-j*a[i]]+j);
                    dp[1][i][k-j*a[i]] = min(dp[1][i][k-j*a[i]],dp[1][i-1][k-j*a[i]]);

                }
            }
        }
//        for(int i = 0;i<=mmax;++i)
//            printf("%d==%d  %d\n",i,dp[0][m][i],dp[1][m][i]);
    int ans;
    for(int i = 0;i<=mmax;++i)
        if(!dp[0][m][i]){ans = i;break;}
    ans--;
    printf("%d\n",ans);


    return 0;
}

 

posted on 2014-08-24 22:31  round_0  阅读(139)  评论(0编辑  收藏  举报

导航