USACO section 3.1 Stamps(dp)

Stamps

Given a set of N stamp values (e.g., {1 cent, 3 cents}) and an upper limit K to the number of stamps that can fit on an envelope, calculate the largest unbroken list of postages from 1 cent to M cents that can be created.

For example, consider stamps whose values are limited to 1 cent and 3 cents; you can use at most 5 stamps. It's easy to see how to assemble postage of 1 through 5 cents (just use that many 1 cent stamps), and successive values aren't much harder:

  • 6 = 3 + 3
  • 7 = 3 + 3 + 1
  • 8 = 3 + 3 + 1 + 1
  • 9 = 3 + 3 + 3
  • 10 = 3 + 3 + 3 + 1
  • 11 = 3 + 3 + 3 + 1 + 1
  • 12 = 3 + 3 + 3 + 3
  • 13 = 3 + 3 + 3 + 3 + 1.

However, there is no way to make 14 cents of postage with 5 or fewer stamps of value 1 and 3 cents. Thus, for this set of two stamp values and a limit of K=5, the answer is M=13.

The most difficult test case for this problem has a time limit of 3 seconds.

PROGRAM NAME: stamps

INPUT FORMAT

 

Line 1: Two integers K and N. K (1 <= K <= 200) is the total number of stamps that can be used. N (1 <= N <= 50) is the number of stamp values.
Lines 2..end: N integers, 15 per line, listing all of the N stamp values, each of which will be at most 10000.

SAMPLE INPUT (file stamps.in)

5 2
1 3

OUTPUT FORMAT

 

Line 1: One integer, the number of contiguous postage values starting at 1 cent that can be formed using no more than K stamps from the set.

SAMPLE OUTPUT (file stamps.out)

13


思路:DP题,计算到达n所使用的最小邮票数,如果不能到达或邮票数不够,则结束,答案即是前一个能达到的数。

           dp[i]=min(dp[i-邮票面值]+1);

 

注意点:最早的思路是贪心,后来发现会漏情况。改用DP话说效率还是蛮高的529MS;不过令我很不解的是第2组数据

               1  4

               1 2 3 5

             居然跑了529ms;实在无语。

 

具体看代码

 

/*
ID:nealgav1
LANG:C++
PROG:stamps
*/
#include<fstream>
#include<algorithm>
#include<cstring>
using namespace std;
ifstream cin("stamps.in");
ofstream cout("stamps.out");
const int mm=2000100;
int dp[mm];
int stam[55];
int m,n;
bool cmp(int a,int b)
{
  return a>b;
}
int main()
{
  cin>>m>>n;
  memset(dp,0,sizeof(dp));
  for(int i=0;i<n;i++)cin>>stam[i];
  sort(stam,stam+n,cmp);///排不排序不影响答案
  for(int i=1;i<mm;i++)
  { int num;
    for(int j=0;j<n;j++)
    { num=i-stam[j];
      if(num>=0)
      { ///达到i所使用的最小邮票数
        if(dp[i]==0||dp[i]>dp[num]+1)
        dp[i]=dp[num]+1;
      }
    }///超过有票数,或无法达到则结束,前一个即是答案
    if(!dp[i]||dp[i]>m){cout<<i-1<<"\n";break;}
  }
}


 

 

 

USER: Neal Gavin Gavin [nealgav1]
TASK: stamps
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.022 secs, 11172 KB]
   Test 2: TEST OK [0.529 secs, 11172 KB]
   Test 3: TEST OK [0.022 secs, 11172 KB]
   Test 4: TEST OK [0.022 secs, 11172 KB]
   Test 5: TEST OK [0.022 secs, 11172 KB]
   Test 6: TEST OK [0.022 secs, 11172 KB]
   Test 7: TEST OK [0.022 secs, 11172 KB]
   Test 8: TEST OK [0.022 secs, 11172 KB]
   Test 9: TEST OK [0.022 secs, 11172 KB]
   Test 10: TEST OK [0.076 secs, 11172 KB]
   Test 11: TEST OK [0.335 secs, 11172 KB]
   Test 12: TEST OK [0.097 secs, 11172 KB]
   Test 13: TEST OK [0.022 secs, 11172 KB]

All tests OK.

YOUR PROGRAM ('stamps') WORKED FIRST TIME! That's fantastic -- and a rare thing. Please accept these special automated congratulations.

Here are the test data inputs:

------- test 1 ----
5 2
1 3
------- test 2 ----
1 4
1 2 3 5
------- test 3 ----
2 4
1 2 4 8
------- test 4 ----
4 4
1 2 4 8
------- test 5 ----
20 1
1
------- test 6 ----
40 3
5 1 2
------- test 7 ----
3 10
29 50 36 43 1 2 4 8 15 22
------- test 8 ----
6 10
1 2 9 31 255 480 4 15 63 127
------- test 9 ----
8 12
1 2 4 15 9 31 63 127 255 511 1000 1999
------- test 10 ----
200 14
1 2 4 15 9 31 63 2100 3500 127 255 511 1000 1999
------- test 11 ----
200 50
1 37 87 14 137 4016 157 5383 7318 8662 7074 2821 5250 9704 8986
1375 6587 5962 7190 339 1981 9719 7012 385 7926 5159 3259 5144 7846 8854
3249 3198 8408 2784 6249 4648 6799 2757 31 4116 7771 3456 3288 3020 3159
8625 747 9745 938 10000
------- test 12 ----
200 15
1 3 14 59 265 358 979 323 846 26 433 832 7950 28 841
------- test 13 ----
200 15
1 1 1 1 1 10 10 10 10 10 100 100 100 100 100

Keep up the good work!

Stamps
Alex Schwendner

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);
}

 

posted @ 2012-10-20 15:37  剑不飞  阅读(259)  评论(0编辑  收藏  举报