• PAT-递归


    递归

    一、分治



    二、递归


    其中重要的是①递归边界:用来返回最简单底层的结果②递归式:用来减少数据规模并向下一层递归


    三、例


    1.全排列

    #include <iostream>
    #include<cstdio>
    using namespace std;
    const int maxn = 11;
    
    //P为当前排列,hashtable记录整数是否已经在P中
    int n, P[maxn], hashTable[maxn] = { false };
    
    //当前处理排列的第index位
    void generateP(int index)
    {
    	//递归边界,已经处理完排列的1~n位
    	if (index == n + 1)
    	{
    		for (int i = 1;i <= n;i++)
    		{
    			//输出当前排列
    			printf("%d", P[i]);
    		}
    		printf("
    ");
    		return;
    	}
    
    	//枚举1~n,试图将x填入P[index]
    	for (int x = 1;x <= n;x++)
    	{
    		//如果x不存在P[0]~P[index]中
    		if (hashTable[x] == false)
    		{
    			//令P的第index位为x,即把x加入当前排列
    			P[index] = x;
    			//记x已在P中
    			hashTable[x] = true;
    			//处理排列的第index+1位
    			generateP(index + 1);
    			//已处理完P[index]为x的子问题,还原状态
    			hashTable[x] = false;
    		}
    	}
    }
    
    int main()
    {
    	//欲输出1~3的全排列
    	n = 3;
    	//从P[1]开始填
    	generateP(1);
    
    	return 0;
    }
    

    2.n皇后问题

    • 朴素算法(暴力法):枚举所有情况,然后判断每一种情况是否合法的做法
    //先采用全排列对皇后所在的行数进行排列
    //再对排列数进行判断,记录合法的次数
    
    #include <iostream>
    #include<cstdio>
    using namespace std;
    const int maxn = 11;
    
    //P为当前排列,hashtable记录整数是否已经在P中,count记录合法的方案数
    int num = 0, n, P[maxn], hashTable[maxn] = { false };
    
    //当前处理排列的第index位
    void generateP(int index)
    {
    	//递归边界,生成一个排列
    	if (index == n + 1)
    	{
    		//flag为true表示当前排列为一个合法方案
    		bool flag = true;
    		//遍历任意两个皇后
    		for (int i = 1;i <= n;i++)
    		{
    			for (int j = i + 1;j <= n;j++)
    			{
    				//如果在一条对角线上,不合法
    				if (abs(i - j) == abs(P[i] - P[j]))
    				{
    					flag = false;
    				}
    			}
    		}
    		//若当前方案合法,令num加1
    		if (flag)num++;
    		return;
    	}
    
    	for (int x = 1;x <= n;x++)
    	{
    		if (hashTable[x] == false)
    		{
    			P[index] = x;
    			hashTable[x] = true;
    			generateP(index + 1);
    			hashTable[x] = false;
    		}
    	}
    }
    
    • 回溯法:在到达递归边界前的某一层,由于一些事实导致已经不需要往任何一个子问题递归,就可以直接返回到上一层
    //先采用全排列对皇后所在的行数进行排列
    //在进行排列时进行判断,不去枚举无效的方案
    //对进行到最后的方案进行计数,即合法的方案数
    
    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxn = 11;
    
    //P为当前排列,hashtable记录整数是否已经在P中,count记录合法的方案数
    int num = 0, n, P[maxn], hashTable[maxn] = { false };
    
    //当前处理排列的第index位
    void generateP(int index)
    {
    	//递归边界,生成一个合法方案
    	if (index == n + 1)
    	{
    		//能到达这里的一定是合法的
    		num++;
    		return;
    	}
    
    	//第x行
    	for (int x = 1;x <= n;x++)
    	{
    		//第x行还没有皇后
    		if (hashTable[x] == false)
    		{
    			//flag为true表示当前皇后不会和之前的皇后冲突
    			bool flag = true;
    
    			//遍历之前的皇后
    			for (int pre = 1;pre < index;pre++)
    			{
    				//第index列皇后的行号为x,第pre列皇后的行号为P[pre]
    				if (abs(index - pre) == abs(x - P[pre]))
    				{
    					//与之前的皇后在一条对角线上,冲突
    					flag = false;
    					break;
    				}
    			}
    
    			//如果可以把皇后放在第x行
    			if (flag)
    			{
    				//令第index列皇后的行号为x
    				P[index] = x;
    				//第x行已被占用
    				hashTable[x] = true;
    				//递归处理第index+1行皇后
    				generateP(index + 1);
    				//递归完毕,还原第x行为未占用
    				hashTable[x] = false;
    			}
    		}
    	}
    
    }
    

    参考-算法笔记-胡凡

  • 相关阅读:
    回流与重绘
    事件循环的一些小啰嗦
    async与await的那些事儿
    数组去重的方法们
    Object的一些常用方法
    JS事件流的一些理解
    关于Ajax的那些记录
    call、bind与apply函数的区别
    继承的一些细碎记载
    计算机基础的小贴士(1)
  • 原文地址:https://www.cnblogs.com/fangzhiyou/p/12663520.html
Copyright © 2020-2023  润新知