您的位置:首页 > 其它

递归基础练习2

2015-12-09 23:39 344 查看
1、QY等人,平时写代码的时候,喜欢吃一种叫“小鱼”的零食,用来提神醒脑(其实没有任何效果,我反而感觉他们越变越笨了)。突然小鱼的厂家做促销。凭3条小鱼尾巴,可以再换一条小鱼。而且可以一直循环下去,QY开心极了,于是拿出整个月的生活费买了N条小鱼。不过因为小鱼非常辣,所以QY每天也只能吃2条,他等某天吃光了,才会在第二天拿着鱼尾巴去换小鱼,然后继续吃。请你计算一下,最后他一共能吃多少天的小鱼呢?输入数据有多组,每组一行,仅包含一个数字N,即QY一开始买入的小鱼的数量。对应每组数据,输出QY能吃多少天,每个结果输出在一行中。

【输入样式】

1

2

3

4

5

【输出样式】

1

1

3

3

5

#include <stdio.h>

/*dayCount函数,计算n条鱼能吃几天,n为鱼的数量,surplus为剩余鱼尾数量*/
int dayCount(int n, int surplus){

int tail = n + surplus; //鱼尾数

if(tail == 0) return 0;

if(tail < 3) return 1;

return (n+1) / 2 + dayCount(tail / 3, tail % 3);

}

int main(){

int n;   //n代表鱼数

while(scanf("%d", &n) != EOF){   //当输入文件结束符时退出循环

printf("%d\n", dayCount(n, 0));

}

return 0;

}


2、简单的背包问题,设有一个背包,可以放入的重量为m。现在有n件物品,质量都为正整数,从n件物品中挑选若干件,使得放入背包重量之和正好为m。找到一组解即可。输入的第一行为物品的总件数和背包的载重量,第二行为各物品的质量。输出放入背包中物品的序号和重量,每行输入一件。

【输入样式】

5 10

1 2 3 4 5

【输出样式】

5 5

4 4

1 1

#include <stdio.h>

#define M 100   //常量,代表最大物品数

int quality[M] = {0};   //存放各物品重量

int backpack[M] = {0};  //记录放入背包物品的序号

/*pack函数,i代表已放入背包物品的数量-1, n为当前物品的序号, m代表背包剩余可放质量*/

int pack(int i, int n, int m){

int judge = 0;  //judge代表是否找到正确结果

if(n  <= 0) return 0;

if(quality[n-1] == m){  //如果当前物品正好填满背包剩余空间,则返回1

backpack[i] = n;

return 1;
}
else if(quality[n-1] < m){  //如果当前物品质量小于背包剩余空间,则将物品放入后继续判断下一个物品

backpack[i] = n;

judge = pack(i+1, n-1, m-quality[n-1]);
}
if(!judge) return pack(i, n-1, m);  //如果当前物品质量小于背包剩余空间,则直接判断下一个物品

return 1;
}

int main(){

int n, m, j;    //n为物品总件数,m为背包载重量,j为循环变量

scanf("%d%d", &n, &m);

for(j = 0; j < n; j++){

scanf("%d", &quality[j]);
}
if(pack(0, n, m)){

j = 0;

while(backpack[j]){

printf("%d %d\n", backpack[j], quality[backpack[j]-1]);

j++;

}
}

return 0;
}


3、任何一个正整数都可以用2的幂次方表示:

如137=2^7+2^3+2^0,同时约定用括号来表示次方,即a^b可表示为a(b),所以137可表示为2(7)+2(3)+2(0),进一步可表示为:7=2^2+2+2^0,3=2+2^0,所以137可表示为2(2(2)+2+2(0))+2(2+2(0))+2(0))。

【输入样式】

1315

【输出样式】

2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

#include <stdio.h>

/*函数功能:将n用2的幂次方表示*/
void powerOfTwo(int n, int m){

if(n == 1){
//程序出口
switch(m){

case 0: printf("2(0)"); break;

case 1: printf("2"); break;

case 2: printf("2(2)"); break;

default:printf("2("); powerOfTwo(m, 0); printf(")");//如果幂次大于二,将幂用2的幂次方表示
}
}
else
{
powerOfTwo(n / 2, m + 1);

if(n % 2) {

switch(m){

case 0: p
4000
rintf("+2(0)"); break;

case 1: printf("+2"); break;

case 2: printf("+2(2)"); break;

default:printf("+2("); powerOfTwo(m, 0); printf(")");
}
}
}
}

int main(){

int n;

scanf("%d", &n);

powerOfTwo(n, 0);

printf("\n");

return 0;
}


4、从楼上走到楼下共有h个台阶,每一步有三种走法:

(1)走一个台阶;(2)走两个台阶;(3)走三个台阶。列举出所有可能方案。

【输入样式】

4

【输出样式】

1111

112

121

13

211

22

31

/*台阶问题*/

#include <stdio.h>

void step(int state[], int i, int h){ //当前走到第i+1步,剩余h级台阶

int j, k;

for(j = 1; j <= 3; j++){ //当前步走j个台阶

state[i] = j;

if(h == j){ //走完一遍即输出

for(k = 0; k <= i; k++){

printf("%d", state[k]);
}
printf("\n");
}
else if(h > j) step(state, i+1, h-j); //台阶还有剩余,继续走下一步

state[i] = 0;

}
}

int main(){

int h; //台阶数

int state[100] = {0}; //存放第i+1步走的台阶数

scanf("%d", &h);

step(state, 0, h);

return 0;
}


5、在8*8的棋盘上,放置8个皇后(棋子),是两两之间互不攻击。所谓互不攻击是说任何两个皇后都要满足:

(1)不在棋盘的同一行;

(2)不在棋盘的同一列;

(3)不在棋盘的同一对角线上。

【输出格式】

15863724

16837425

17468253

17582463

24683175

……

(注:共有92组解,这里不一一列举。)

/*八皇后问题*/

#include <stdio.h>

int array[9] = {0}; //存放每个皇后所在列
int state[9] = {0}; //标记该列是否安全
int down[14] = {0}; //标记该右对角线是否安全
int up[14] = {0}; //标记该左对角线是否安全

void queen(int row){ //为第row个皇后安排位置

int col, i;

for(col = 1; col <= 8; col++){ //尝试将每个col安排给当前皇后

if(up[row+col-2] != 0 || down[col-row+7] != 0 || state[col] != 0) continue; //发生冲突,尝试下一个col

array[row] = col;

state[col] = 1;

up[row+col-2] = 1;

down[col-row+7] = 1;

if(row == 8) {

for(i = 1; i <= 8; i++){

printf("%d", array[i]);
}
printf("\n");
}
else queen(row + 1);

//回溯,恢复分配前状态
state[col] = 0;

array[row] = 0;

up[row+col-2] = 0;

down[col-row+7] = 0;
}
}

int main(){

queen(1);

return 0;
}


6、数的全排列问题,将n个数字1,2,3,…,n的所有排列按字典顺序枚举出来。

【输入格式】

3

【输出格式】

123

132

213

231

312

321

/*全排列问题*/

#include <stdio.h>

void arrange(int state[][10], int i, int n){ //为第i个盒子放小球

int j, k;

for(j = 1; j <= n; j++){ //将第j个小球放入第i个盒子

if(state[1][j] != 0) continue;

state[0][i] = j;

state[1][j] = 1;

if(i == n){

for(k = 1; k <= n; k++){

printf("%d", state[0][k]);
}
printf("\n");
}
else arrange(state, i+1, n);

//回溯,将第i个盒子置空,第j个小球恢复原始状态
state[0][i] = 0;

state[1][j] = 0;
}

}

int main(){

int n;

int state[2][10] = {0}; //第一行保存第i个盒子放的数,第二行标记第j个小球当前状态

scanf("%d", &n);

arrange(state, 1, n);

return 0;
}


7、数的组合问题。从1,2,…,n中取出m个数,将所有组合按照字典顺序列出。

【输入格式】

3 2

【输出格式】

12

13

23

/*数的组合问题*/

#include <stdio.h>

/*将第j个小球放入第i个盒子*/
void combine(int *com, int i, int j, int n, int m){

int k;

for(; j <= n; j++){

com[i] = j;

if(i+1 == m){

for(k = 0; k < m; k++){

printf("%d", com[k]);
}
printf("\n");
}
else combine(com, i+1, j+1, n, m);

com[i] = 0;
}
}

int main(){

int n, m;

int com[100] = {0};

scanf("%d%d", &n, &m);

combine(com, 0, 1, n, m);

return 0;
}


8、G将军有一支训练有素的军队,这个军队除开G将军外,每名士兵都有一个直接上级(可能是其他士兵,也可能是G将军)。现在G将军将接受一个特别的任务,需要派遣一部分士兵(至少一个)组成一个敢死队,为了增加敢死队队员的独立性,要求如果一名士兵在敢死队中,他的直接上级不能在敢死队中。G将军有多少种派出敢死队的方法。注意,G将军也可以作为一个士兵进入敢死队。输入的第一行包含一个整数n,表示包括G将军在内的军队的人数。军队的士兵从1至n编号,G将军编号为1。接下来n-1个数,分别表示编号为2, 3, …, n的士兵的直接上级编号,编号i的士兵的直接上级的编号小于i。输出一个整数,表示派出敢死队的方案数。由于数目可能很大,你只需要输出这个数除10007的余数即可。

【输入格式】

3

1 1

【输出格式】

4

样例说明

这四种方式分别是:

1. 选1;

2. 选2;

3. 选3;

4. 选2, 3。

数据规模与约定

对于20%的数据,n ≤ 20;

对于40%的数据,n ≤ 100;

对于100%的数据,1 ≤ n ≤ 100000。

/*这里采用了链栈存储,读者可更改为顺序栈存储*/

//LinkStack.h

struct Node{

int data;

Node *next;
};

class LinkStack
{
public:
LinkStack()

{top = NULL;}

~LinkStack();

void push(int x);

int pop();

bool isExist(int m);

void printStack();

private:

Node *top;
};

//LinkStack.cpp

#include <iostream>

#include "LinkStack.h"

using namespace std;

/*析构函数*/
LinkStack::~LinkStack()
{
Node *p;
while(top){

p = top;
top = top->next;
delete p;
}
}

/*压栈*/
void LinkStack::push(int x)
{
Node *p;
p = new Node;
p->data = x;
p->next = top;
top = p;
}

/*弹栈*/
int LinkStack::pop()
{
int data;
Node *p;
if(!top) cout << "下溢";
p = top;
top = p->next;
data = p->data;
delete p;
return data;
}

/*判断栈中是否存在元素m*/
bool LinkStack::isExist(int m){

Node *p = top;

while(p){

if(p->data == m) return true;
p = p->next;
}
return false;
}

/*遍历栈中元素,用于编程时对程序的检验*/
void LinkStack::printStack()
{
Node *p;
p = top;
while(p)
{
cout << p->data;
p = p->next;
}
cout << endl;
}

//Squad.cpp

#include <iostream>

#include "LinkStack.h"

using namespace std;

const int M = 100001; //树的最大结点数

/*count函数:返回值为空,tree指针指向树结构,stack引用链栈结构,m表示当前处理的士兵,n代表最后一个士兵
功能:计算编号在m到n可派出敢死队的方案数。
*/
void count(int *tree, LinkStack &stack, int m, int n){

for(; m <= n; m++){

if(stack.isExist(tree[m])) continue;

stack.push(m); //将可派出的士兵进栈

tree[0] = (tree[0]+1) % 10007; //每进栈一次,代表生成一种新的方案

count(tree, stack, m+1, n); //计算m+1到n可派出敢死队的方案数

stack.pop(); //回溯,即出栈
}
}

int main(){

int tree[M] = {0}; //用顺序表存储树,数据域存放其双亲结点,下标代表士兵编号
int n; //士兵的数量
LinkStack stack; //用链栈存放当前选中的士兵

cin >> n;

for(int i = 2; i <= n; i++){

cin >> tree[i];
}
count(tree, stack, 1, n); //计算编号在m到n可派出敢死队的方案数

cout << tree[0] << endl; //树的0号元素存储可生成的方案数

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归 基础练习