USACO Stamps

1、这是一道DP,我感觉设计好状态真的很重要,刚开始我的dp【i】是表示“能否凑成数额i”,这就要求一定要等所有面值都算完后,再从头开始搜索看哪个面值不能凑成。比如面值56凑不成,而可能的面值有2000000种,那是巨大的浪费,算法是O(K*K*maxn*N)的,会超时。

2、另一种状态是用dp【i】表示“凑成i最少需要的邮票张数”,这样只要把初始值设为INF,然后从头开始递推即可,一旦不满足要求,立即输出。

3、还有发现gdb的调试功能真的很强大,用wa i+c指令就能在变量i改变的时候自动暂停~我真是太喜欢这个功能啦~

/*
ID:mrxy564
PROG:stamps
LANG:C++
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=~0U>>2;
int a[55],K,N,dp[2000010],maxn=0,minn=INF;
int main(){
 freopen("stamps.in","r",stdin);
 freopen("stamps.out","w",stdout);
 scanf("%d%d",&K,&N);
 for(int i=0;i<N;i++){
  scanf("%d",&a[i]);
  maxn=max(maxn,a[i]);
  minn=min(minn,a[i]);
 }
 for(int i=0;i<=maxn*K+1;i++)
  dp[i]=INF;
 dp[0]=0;
 for(int j=0;j<=maxn*K+1;j++){
    for(int k=0;k<N;k++)
    if(j>=a[k])
                   dp[j]=min(dp[j-a[k]]+1,dp[j]);
       if(dp[j]>K){
     printf("%d\n",j-1);
     break;
    }
 }
 return 0;
}

官方题解:

This problem is simply begging for a DP solution. We keep an array "minstamps" such that minstamps[i] is the minimum number of stamps needed to make i cents. For each stamp type, we try adding one stamp of that type to each number of cents that we have already made. After we have found the minimum number of stamps needed to make any given number of cents, we find the smallest number of cents that we cannot make with the given number of stamps, and then we output one less then that.

#include <fstream.h>

const int BIG = 10000;

short   minstamps[10000 * (200 + 3) + 3];
int     stamps;
int     value[200];
int     number;


int 
main ()
{

    ifstream filein ("stamps.in");
    filein >> number >> stamps;
    int     biggest = -1;
    for (int i = 0; i < stamps; ++i) {
	filein >> value[i];
	if (biggest < value[i]) {
	    biggest = value[i];
	}
    }
    filein.close ();

    for (int i = 0; i <= biggest * number + 3; ++i) {
	minstamps[i] = BIG;
    }

    minstamps[0] = 0;
    for (int i = 0; i < stamps; ++i) {
	for (int j = 0; j <= biggest * number; ++j) {
	    if (minstamps[j] < number) {
		if (minstamps[j + value[i]] > 1 + minstamps[j]) {
		    minstamps[j + value[i]] = 1 + minstamps[j];
		}
	    }
	}
    }


    int     string = 0;
    while (minstamps[string + 1] <= number) {
	++string;
    }

    ofstream fileout ("stamps.out");
    fileout << string << endl;
    fileout.close ();

    return (0);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值