递归总结2

问题 C: 【递归】拆分自然数

题目

“天下熙熙,皆为利来;天下攘攘,皆为利往”,监狱里的暗势力划分地盘的目的无非是为了获取利益,他们分配利益的方式是基于这样一个准则:设总利益为自然数N,则任何一个大于1的N,总可以拆分成若干个小于N的自然数之和,求出N的所有拆分后选择最合适的一种进行分配,例如当N=3时,有两种划分,即3=1+2和3=1+1+1。试求出N的所有拆分。
输入
一个整数即N,N<100。
输出
输出每一种划分方案,每种划分方案占一行,最后一行为方案总数。
样例输入 Copy
3
样例输出 Copy
3=1+1+1
3=1+2
2

思路:我们可以看出输入后面的项大于等于前面的项,那么第一项从1开始遍历到n/2,每一次值val减去i(i从前一项的值开始遍历到当前剩下的值),直到val=0时输出

#include <cstdio>
#include <iostream>
using namespace std;
int num[100];
int cnt=0;
void print(int index)
{
    printf("%d=%d",num[0],num[1]);
    for(int i=2;i<=index;i++) printf("+%d",num[i]);
    cout<<'\n';
}
void solve(int index,int val)
{
    if(val==0)///递归边界,当前值为0了输出
    {
        print(index);
        cnt++;
        return;///回溯
    }
    for(int i=num[index]; i<=val; i++)///减去的值从num[index]到val遍历
    {
        num[index+1]=i;///下一项赋值
        solve(index+1,val-i);///向下一层搜索
    }
}
int main()
{
    int n;cin>>n;
    num[0]=n;
    for(int i=1;i<=n/2;i++)
    {
        num[1]=i;//第一项从1开始遍历到n/2
        solve(1,n-i);
    }
    cout<<cnt<<endl;
}


问题 E: 【递归】冲突

题目:

监狱的每间牢房是一个不超过4×4的正方形,里面设有一些障碍,牢房里住着的犯人脾气都很大,只要两个犯人位于同一行或同一列即会发生冲突,但障碍物可以阻挡同行或同列犯人的冲突。问最多可放几个犯人而不会发生冲突。如下图所示,左边表示初始牢房样,右边4个显示了摆放方案,当然,最后两个方案是错误的。

输入

有多组测试数据,每组数据第一行为一个整数N表示牢房大小。随后N行描述牢房,其中X表示障碍。
所有测试数据结束的标志为0。

输出

输出最多可放的犯人数。

样例输入 Copy
4
.X…

XX…

2
XX
.X
3
.X.
X.X
.X.
3

.XX
.XX
4




0

样例输出 Copy

5
1
5
2
4

思路:染色+搜索+回溯,若该位置可以放囚犯,则对该行该列染色,遇到’X’停止,然后看该行是否还能放囚犯,若行,则继续染色,然后回溯,每次到达下一层时更新答案

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,maxn=0;
char a[10][10];
bool color(int x,int y)///染色函数,注意'.'和'*'都可以染色
{
    int i=x,j=y;
    while((a[x][j]=='.'||a[x][j]=='*')&&j<=n) a[x][j++]='*';
    j=y-1;  while((a[x][j]=='.'||a[x][j]=='*')&&j>=1) a[x][j--]='*';
    while((a[i][y]=='.'||a[i][y]=='*')&&i>=1) a[i--][y]='*';
    i=x+1;  while((a[i][y]=='.'||a[i][y]=='*')&&i<=n) a[i++][y]='*';
    for(int i=1;i<=n;i++) if(a[x][i]=='.') return true;///检测是否还有可以染色的区域
    return false;
}
void getrid(int x,int y)///去除染色,为'*'就去除
{
    int i=x,j=y;
    while(a[x][j]=='*'&&j<=n) a[x][j++]='.';
    j=y-1;  while(a[x][j]=='*'&&j>=1) a[i][j--]='.';
    while(a[i][y]=='*'&&i>=1) a[i--][y]='.';
    i=x+1;  while(a[i][y]=='*'&&i<=n) a[i++][y]='.';
}

void solve(int row,int ans)
{

    maxn=max(maxn,ans);///更新答案
    if(row==n+1) return;
    for(int i=1;i<=n;i++)
    {
        if(a[row][i]=='.')///可以发
        {
            if(color(row,i))///染色并检测是否还有能放的
            {
                for(int j=1;j<=n;j++)
                {
                    if(a[row][j]=='.')///还有能放的,染色
                    {
                        color(row,j);
                        solve(row+1,ans+2);///向下一层搜索
                        getrid(row,j);///回溯
                    }
                }
            }
            else solve(row+1,ans+1);///向下一层搜索
            getrid(row,i);///回溯
        }
    }
    solve(row+1,ans);///这层不染,向下一层搜索
}
int main()
{
    while(cin>>n)
    {
        if(n==0) break;
        memset(a,0,sizeof(a));
        maxn=0;
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j];
        solve(1,0);
        cout<<maxn<<endl;
    }
    return 0;
}


问题 I: 【递归】放苹果

题目

楚继光刚把油拿到厨房,老妈又大声喊道:“快去把苹果洗了放到盘子里去。”

楚继光要把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5、1、1和1、5、1 是同一种分法。

输入

第1行为一个整数,表示测试数据的数目(测试数据的数目t(0 ≤ t ≤20),第2行为M和N(M和N,以空格分开。1≤M,N≤10)。

输出

输出有多少种不同分法。

样例输入 Copy

1
7 3

样例输出 Copy

8

代码

#include<iostream>
using namespace std;
int getans(int m,int n)///把m个苹果放进n个盘子的方法总数
{
	if(m<n) return getans(m,m);///如果盘子数目多于苹果数,getans(m,n)=getans(m,m)
	if(m==0) return 1;///如果苹果数目为零,只有1种方法
	if(n==0) return 0;///如果盘子为空,方法数为0
	return getans(m,n-1)+getans(m-n,n);///有空盘和无空盘
}
int main()
{
	int t,m,n;
	cin>>t;
	while(t--)
	{
		cin>>m>>n;
		cout<<getans(m,n)<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Spidy_harker/article/details/102750958
今日推荐