递归基础练习2

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: printf("+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;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值