递推(三):POJ中的三道递推例题POJ 1664、POJ 2247和POJ 1338

【例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;
}

原文地址:https://www.cnblogs.com/cs-whut/p/11022759.html

时间: 2024-10-06 15:51:29

递推(三):POJ中的三道递推例题POJ 1664、POJ 2247和POJ 1338的相关文章

[ACM] POJ 2506 Tiling (递推,大数)

Tiling Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7487   Accepted: 3661 Description In how many ways can you tile a 2xn rectangle by 2x1 or 2x2 tiles? Here is a sample tiling of a 2x17 rectangle. Input Input is a sequence of lines,

在 Asp.NET MVC 中使用 SignalR 实现推送功能 [转]

在 Asp.NET MVC 中使用 SignalR 实现推送功能 罗朝辉 ( http://blog.csdn.net/kesalin ) CC许可,转载请注明出处 一,简介 Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送请求或使用轮询技术来获取消息. 可访问其官方网站:https://github.com/SignalR/ 获取更多资讯. 二,实现机制

javascript基础程序(算出一个数的平方值、算出一个数的阶乘、输出!- !- !- !- !- -! -! -! -! -! 、函数三个数中的最大数)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script> /* 算出一个数的平方值 function add(a){ var b=Math.sqrt(a); return b; } alert(add(3));*/ /*// 算出一个数的阶乘 func

多线程(三) java中线程的简单使用

============================================= 原文链接:多线程(三) java中线程的简单使用 转载请注明出处! ============================================= java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依旧是实现了Runnabel接口.考虑到java的

GoEasy实现web实时推送过程中的自动补发功能

熟悉GoEasy推送的朋友都知道GoEasy推送能够非常准确稳定地推送到客户端.在后台功能中查看接收信息详情时,可有谁注意到有时候在发送记录里有一个红色的R标志?R又代表的是什么意思呢? 在推送的过程中,不免有些用户或客户端当时的网络状态不太好,这些外在的因素会导致用户漏收到一些消息.GoEasy也考虑到了这些问题,他们是怎么解决这个问题的呢? 细心的朋友可能注意到了,在后台功能中,可以查看每个在线client的断开重连情况. GoEasy记录每个client的在线重连情况就可以判断哪些客户端还

三数中找最大值

static void Main11三数中找最大值(string[] args) { //1.输入三个数,找出最大的输出 Console.WriteLine("请输入第一个数"); int a = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("请输入第二个数"); int b = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("

if语句求三个数中最大的

Console.WriteLine("请输入第一个数:"); int a = Convert.ToInt32( Console.ReadLine()); Console.WriteLine("请输入第二个数:"); int b = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("请输入第三个数:"); int c = Convert.ToInt32(Console.ReadLine(

OpenCv学习笔记(三)---OpenCv中基本数据类型--Point,Size,Rect,Scalar,Vec3b类类型的详细解释及其OpenCv中源代码的详细分析

/********************************************************************************************* 程序功能: OpenCv的基本数据结构源代码的解读,我们常用的OpenCv的基本数据结构有六种: 1--Point类 2--Size类 3--Rect类 4--Scalar类 5--Vec3b--向量模板类 6--Range类 编写环境: OpenCv2.4.8+VS2010 地点时间: 陕西师范大学 201

选出三个数中的最大数

using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace 从三个数中选出最大数{ class Program { static void Main(string[] args) { Console.WriteLine ("请输入三个数:"); Console.Write("请输入第一个数:"); string str_a = Console