【例9】放苹果(POJ 1664)
Description
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Output
对输入的每组数据M和N,用一行输出相应的K。
Sample Input
1
7 3
Sample Output
8
(1)编程思路。
设f[m][n]表示把m个苹果放到n个盘子里的不同方法的种数。
1)当盘子数n为1的时候,只有一种放法,就是把所有苹果放到一个盘子里。
2)当苹果数m为1的时候,也只有一种放法,因为盘子之间并无顺序,所以不管这个苹果放在哪个盘子里,结果都算一个。
3)当m<n时,m个苹果最多只能放到m个盘子中去(一个盘子里放一个),盘子有多余的。此时,实际上就相当于把m个苹果放到m个盘子里一样,也就是f[m][m]。
4)当m>=n时,可分两种情况讨论。一种是至少有一个盘子里不放苹果,这就相当于f[m][n-1];另一种是先取出n个苹果一个盘子里放一个,再将剩下的m-n个苹果放到n个盘子里去,即f[m-n][n]。
综上所述,可得到递推关系式如下:
f[m][n]=1 当m=1或n=1时
f[m][n] = f[m][m] 当m<n时
f[m][n] = f[m-n][n] + f[m][n-1] 当m>=n时;
另外,当m=0或n=0时,定义f[m][n]=1。即有盘子没苹果放,或者有苹果没有盘子装,都是一种可能存在的情况。这个可以特殊处理,就像0的阶乘定义为1一样。
(2)源程序。
#include <iostream>
using namespace std;
int main()
{
int f[11][11];
int t,n,m,i,j;
for (i=0;i<=10;i++)
{
f[i][0]=1;
f[i][1]=1;
f[0][i]=1;
f[1][i]=1;
}
for (i=2;i<=10;i++)
for(j=2;j<=10;j++)
{
if(i>=j)
f[i][j]=f[i][j-1]+f[i-j][j];
if(i<j)
f[i][j]=f[i][i];
}
cin>>t;
while(t--)
{
cin>>m>>n;
cout<<f[m][n]<<endl;
}
return 0;
}
【例10】Humble Numbers (POJ 2247)
Description
A number whose only prime factors are 2,3,5 or 7 is called a humble number. The sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, shows the first 20 humble numbers.
Write a program to find and print the nth element in this sequence.
Input
The input consists of one or more test cases. Each test case consists of one integer n with 1 <= n <= 5842. Input is terminated by a value of zero (0) for n.
Output
For each test case, print one line saying "The nth humble number is number.". Depending on the value of n, the correct suffix "st", "nd", "rd", or "th" for the ordinal number nth has to be used like it is shown in the sample output.
Sample Input
1
2
3
4
11
21
100
5842
0
Sample Output
The 1st humble number is 1.
The 2nd humble number is 2.
The 3rd humble number is 3.
The 4th humble number is 4.
The 11th humble number is 12.
The 21st humble number is 28.
The 100th humble number is 450.
The 5842nd humble number is 2000000000.
(1)编程思路。
根据数列的定义,数列中的一个数应该是其前面某个数乘以2、3、5或者7的结果。因此,可以定义一个数组num[5843]来顺序保存数列中的数,数组里面的每一个元素的值是前面的某个元素值乘以2、3、5或者7得到。
问题的关键是怎样确保数组里面的各元素是按值的大小依次生成的。
假设数组中已经有若干个数列中的元素,排好序后存在数组中。把数列中现有的最大的数记做M。由于数列中的下一个数肯定是前面某一个数乘以2、3、5或者7的结果。首先考虑把已有的每个数乘以2。在乘以2的时候,能得到若干个结果小于或等于M的。由于数组中的元素是按照顺序生成的,小于或者等于M的数肯定已经在数组中了,不需再次考虑;还会得到若干个大于M的结果,但只需要第一个大于M的结果,因为数组中的元素是按值从小到大顺序生成的,其他更大的结果可以以后再说,记下得到的第一个乘以2后大于M的数M2。同样,把已有的每一个数乘以3、5和7,记下得到的第一个大于M的结果M3、M5和M7。那么,数列中下一个数应该是M2、M3、M5和M7四个数的最小者。
事实上,上面所说的把数组中已有的每个数分别都乘以2、3、5和7,是不需要的,因为已有的数是按顺序存在数组中的。对乘以2而言,肯定存在某一个数T2,排在它之前的每一个数乘以2得到的结果都会小于已有最大的数,在它之后的每一个数乘以2得到的结果都会太大。因此,只需要记下这个数的位置P2,同时每次生成一个新的数列中的数的时候,去更新这个P2。对乘以3、5和7而言,存在着同样的P3、P5和P7。
定义变量index保存当前待生成的数在数列中的序号,显然,已生成的数列中的最大元素为Num[curIndex-1]。
定义4个指针变量int *p2,*p3,*p5,*p7;分别指向数组中的4个元素,排在所指元素之前的每一个数乘以2(或3、或5、或7)得到的结果都会小于已有最大的数num[index-1],在所指元素之后的每一个数乘以2(或3、或5、或7)得到的结果都会太大。
初始时,num[1] = 1、index =2、p2 = p3 = p5 = &num[1]。
生成第index个元素的方法为:
if (*p2 * 2<*p3 * 3) min = *p2 * 2;
else min= *p3 * 3;
if (min> *p5 * 5) min=*p5 * 5;
if (min> *p7 *7) min=*p7 * 7;
num[index] = min;
第index个元素生成后,需要对指针p2、p3、p5和p7进行更新,更新方法为:
if(num[index]==*p2*2) p2++;
if(num[index]==*p3*3) p3++;
if(num[index]==*p5*5) p5++;
if(num[index]==*p7*7) p7++;
(2)源程序。
#include<iostream>
using namespace std;
int main()
{
int num[5843],index,min,n;
int *p2,*p3,*p5,*p7;
p2=p3=p5=p7=&num[1];
num[1]=1;
for(index=2;index<=5842;index++)
{
if (*p2 * 2<*p3 * 3) min = *p2 * 2;
else min= *p3 * 3;
if (min> *p5 * 5) min=*p5 * 5;
if (min> *p7 *7) min=*p7 * 7;
num[index] = min;
if(num[index]==*p2*2) p2++;
if(num[index]==*p3*3) p3++;
if(num[index]==*p5*5) p5++;
if(num[index]==*p7*7) p7++;
}
while(cin>>n && n!=0)
{
if (n%10 == 1 && n%100 != 11)
cout<<"The "<<n<<"st humble number is "<<num[n]<<"."<<endl;
else if (n%10 == 2 && n%100 != 12)
cout<<"The "<<n<<"nd humble number is "<<num[n]<<"."<<endl;
else if (n%10 == 3 && n%100 != 13)
cout<<"The "<<n<<"rd humble number is "<<num[n]<<"."<<endl;
else
cout<<"The "<<n<<"th humble number is "<<num[n]<<"."<<endl;
}
return 0;
}
【例11】Ugly Numbers (POJ 1338)
Description
Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ...
shows the first 10 ugly numbers. By convention, 1 is included.
Given the integer n,write a program to find and print the n'th ugly number.
Input
Each line of the input contains a postisive integer n (n <= 1500).Input is terminated by a line with n=0.
Output
For each line, output the n’th ugly number .:Don’t deal with the line with n=0.
Sample Input
1
2
9
0
Sample Output
1
2
10
(1)编程思路。
根据数列的定义,数列中的一个数应该是其前面某个数乘以2、3或者5的结果。因此,可以定义一个数组num[1501]来顺序保存数列中的数,数组里面的每一个元素的值是前面的某个元素值乘以2、3或者5得到。
阅读体会例10中的编程思路,将例10的源程序略作修改即可。
(2)源程序。
#include<iostream>
using namespace std;
int main()
{
int num[1501],index,min,n;
int *p2,*p3,*p5;
p2=p3=p5=&num[1];
num[1]=1;
for (index=2;index<=1500;index++)
{
if (*p2 * 2<*p3 * 3) min = *p2 * 2;
else min= *p3 * 3;
if (min> *p5 * 5) min=*p5 * 5;
num[index] = min;
if(num[index]==*p2*2) p2++;
if(num[index]==*p3*3) p3++;
if(num[index]==*p5*5) p5++;
}
while(cin>>n && n!=0)
{
cout<<num[n]<<endl;
}
return 0;
}