各算法思想总结

数据结构与算法归纳总结

1.枚举

1.1 例题: 求24

/* 递归边界:只有一个数判断是否等于24,等于24不能用==判断 只能用<某个极限 两层遍历一个选取两个数将剩下的数放在一个数组中B[] 将前两个数运算的集合放在b数组的末尾 提取的两个数有 a[i]+a[j] a[i] - a[j] a[j] - a [i] a[i]/a[j] a[j] /a[i] a[i]*a[j] 任意情况成立则 总成立 所有情况不成立则不成立 */

#include<iostream>
#include<cmath> 
using namespace std;
double a[5];
#define EPS 1e-6
bool isZero(double x)
{
	return fabs(x) <= EPS;
}
bool count24(double a[], int n)
{
	if( n == 1)   				//边界条件 
	if(isZero(a[0] - 24))
		return true;
	else
		return false;
		
	double b[5];
	for(int i = 0;i  < n-1;i++ )    //a[i] 和a[j] 用来运算的两个数 
	{
		for(int j = i+1; j < n; ++j)
		{
			int m = 0;  	// 还剩m个数 m = n-2; 
			for( int k = 0; k < n; k++)
				if(k != i && k != j)     //枚举把其余数放入b中 
					b[m++] = a[k];
					b[m] = a[i] + a[j]; 
				if(count24(b,m+1))
					return true;
					b[m] = a[i]-a[j]; 
				if(count24(b,m+1))
					return true;
					b[m] = a[j] - a[i]  ;
				if(count24(b,m+1))
					return true;
					b[m] = a[i]*a[j];
				if(count24(b,m+1)) 
					return true;
				if(!isZero(a[j])) 
				{
					b[m] = a[i] / a[j];
					if(count24(b,m+1))
						return true;
				}
				if(!isZero(a[i]))
				{
					b[m] = a[j]/a[i];
					if(count24(b,m+1))
						return true;
				}
		}
		return false;
	}
	
}
int main()
{
	for(int i = 0; i < 4; i++)
	{
		cin >> a[i];
	}
	if(count24(a,4))
		cout << "true" ;
	else
		cout << "false";
 } 

1.2 设计思想

1.将问题所有的可能性一一列举

2.保留合适的,排除不合适的。

PS:列举所有的数字组合情况,然后进行判断。

1.3 算法模板

循环
情况: <S>
for(x:S)
{
	if judge(x) == true;
    save x;
    else
    no do;
}

递归遍历情况
void f()
{
    if(S.empty())
        return ;
    取出S中的一个x
   	if(judge(x))
        save
    else
        f(x+1)}


2.分治

2.1 例题 快速排序

#include<iostream>
#include<algorithm>
using namespace std;
void quick_sort(int a[], int s, int e)
{
	if(s >= e)
		return ;
	int k = a[s];
	int i = s,j = e;
	while(i != j)
	{
		while(j > i && a[j] >= k)
			--j;
			swap(a[i],a[j]);
		while(i < j && a[i] <= k)
			++i;
			swap(a[i],a[j]);
	}
	quick_sort(a,s,i-1);
	quick_sort(a,i+1,e);
}
int main()
{
	int a[8]={4,5,2,1,8,9,6};
	quick_sort(a,0,8);
	for(int i = 0;i < 8; i++)
		cout << a[i];
 } 
/* 7 8 5 6 4 1 2 3 9 */

2.2 设计思想

  1. 父问题能无限划分成小问题,且子问题之间不相互影响。
  2. 所有子问题的解集合能得到父问题的解

在上述快速排序中,每一个元素的左边小于自己,右边大于自己即排序完成。

2.3 算法模板

begin  {分治过程开始}
    if ①问题不可分 then ②返回问题解  
     else begin
          ③从原问题中划出含一半运算对象的子问题1;
          ④递归调用分治法过程,求出解1;
          ⑤从原问题中划出含另一半运算对象的子问题2;
          ⑥递归调用分治法过程,求出解2; 
          ⑦将解1、解2组合成整修问题的解;  
        end;
   end; {结束}

3.递归

3.1 题目 N皇后问题

#include<iostream>
#include<cmath>
#include<stdio.h>
using namespace std;
int room[9][9],lie[9],sum = 0;  //data 
void fun(int t)  //t hang find lie
{
	if(t == 9)  
	{
		int SUM = 0;
		for(int i =1;i < 9;i++)
		SUM += room[i][lie[i]];
		if(SUM > sum)
		sum  = SUM;
		return ;
	}
	int i;
	for(i = 1;i <= 8;i++)
	{
		int j;
		for(j = 1;j < t;j++)
		{
			if(i == lie[j]||abs(lie[j] - i) == abs(j - t))	
			break;
		}
		if(t == j)
		{
			lie[t] = i;
			fun(t+1);
		}
	}
	
}
int main()
{
	freopen("input.txt","r",stdin);
	for(int i = 1;i < 9;i++)
	for(int j = 1;j < 9;j++)
	cin >> room[i][j];
	fun(1);
	cout << sum << endl;
}

3.2 算法思想

3.2.1结构性递归

  1. 类似二叉树的不断分支
  2. 先左节点,后右节点

3.2.2 过程型递归

  1. 汉诺塔问题。

3.2.3 总结

不论结构型递归还是过程性递归,都必须要抛弃程序的细节,只关注程序的功能

3.3 模板

过程性递归
void fun(int n)
{
	if(达到出口的条件)
    {
        判断是否符合要求
            return}
    fun(n+1);
}
结构型递归
void dfs()
{
    if(达到根节点返回)
	dfs(左边)dfs(右边)deal(自己)
}

4.动态规划

4.1 案例 未命名湖畔的烦恼

#include<stdio.h>
typedef long long ll;  
using namespace std;  
  
  
int f(int m,int n)  
{  
    if(m < n)  
        return 0;  
    if(n == 0)  
        return 1;  
    return f(m-1,n) + f(m,n-1);  
}  
  
int main()  
{  
    int m,n;  
    while(scanf("%d%d",&m,&n) != EOF)  
    {  
        int sum = f(m,n);  
        printf("%d\n",sum);  
    }  
    return 0;  
}  

4.2 算法思想

  1. 问题可以递归实现也可以滚动数组实现
  2. 动态规划算法注意可以求得得边界
  3. 原始问题是边界得重复迭代

4.3 算法模板

递归实现
int f(int m,int n)  
{  
    if(m == 0)  
        return 0;  
    if(n == 0)  
        return 1;  
    return f(m-1,n) + f(m,n-1);  
} 
滚动数组实现
a[N][N]
for(i->N)
    a[i][0]=num;
	a[0][i]=num;
for(i:N)
{
    for(j:N)
    {
        a[i][j] = max(a[i-1][j],a[i][j-1]);
    }
}

5.广度优先搜索

5.1 案例 学霸的迷宫

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
struct pos{
	int x, y;
	int num;
};
int n, m;
char map[550][550];
int vis[550][550];
int dir[4][2] = {1, 0, 0, -1, 0, 1, -1, 0};
int pre[550][550];
char str[5] = {"DLRU"};
void bfs() {
	queue <pos> q;
	pos t;
	t.x = 1, t.y = 1, t.num = 0;
	q.push(t);
	vis[1][1] = 1;
	pre[1][1] = -1;
	while(!q.empty()) {
		t = q.front();
		q.pop();
		if(t.x == n && t.y == m) {
			printf("%d\n", t.num);
			return ;
		}
		int i, j;
		pos tt;
		for(i = 0; i < 4; i++) {
			tt.x = t.x + dir[i][0];
			tt.y = t.y + dir[i][1];
			tt.num = t.num + 1;
			if(tt.x >= 1 && tt.x <= n && tt.y >= 1 && tt.y <= m && map[tt.x][tt.y] == '0' && vis[tt.x][tt.y] == 0) {
				pre[tt.x][tt.y] = i;
				q.push(tt);
				vis[tt.x][tt.y] = 1;
			}
		}
	}
}
void path(int x, int y) {
	if(x == 1 && y == 1) return;
	path(x - dir[pre[x][y]][0], y - dir[pre[x][y]][1]);
	printf("%c", str[pre[x][y]]);
}
int main () {
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	scanf("%d %d", &n, &m);
	getchar();
	int i, j;
	for(i = 1; i <= n; i++) {
		for(j = 1; j <= m; j++) {
			scanf("%c", &map[i][j]);
		}
		getchar();
	}
	bfs();
	path(n, m);
	return 0;
}

5.2算法思想

  1. 从一点出发找到附近的节点看是否符合要求
  2. 然后从相邻的节点出发,继续BFS

PS:从起始位置出发,一步一步搜索,每步标记自己从哪里走过来的。

5.3 算法模板

q.push(head);
while(!q.empty())
{
	temp=q.front();
	q.pop();
	if(tempÎ为目标状态)
		输出或记录
	if(temp不合法 )
		continue;
	if(temp合法)
		q.push(temp+¦Δ ); 
}

6. 深度优先搜索

6.1 案例 N皇后

#include<iostream>
#include<cmath>
#include<stdio.h>
using namespace std;
int room[9][9],lie[9],sum = 0;  //data 
void fun(int t)  //t hang find lie
{
	if(t == 9)  
	{
		int SUM = 0;
		for(int i =1;i < 9;i++)
		SUM += room[i][lie[i]];
		if(SUM > sum)
		sum  = SUM;
		return ;
	}
	int i;
	for(i = 1;i <= 8;i++)
	{
		int j;
		for(j = 1;j < t;j++)
		{
			if(i == lie[j]||abs(lie[j] - i) == abs(j - t))	
			break;
		}
		if(t == j)
		{
			lie[t] = i;
			fun(t+1);
		}
	}
	
}
int main()
{
	freopen("input.txt","r",stdin);
	for(int i = 1;i < 9;i++)
	for(int j = 1;j < 9;j++)
	cin >> room[i][j];
	fun(1);
	cout << sum << endl;
}

6.2 设计思想

  1. 从一个节点出发,不断向下寻找,
  2. 经过的节点标记走过
  3. 遇到无法寻找即返回。

6.3 算法模板

void dfs(状态A)
{
	if(A不合法)
		return;
	if(A为目标状态)
		输出或记录路径
	if(A不为目标状态)
		dfs(A+Δ ) 
 } 
    原文作者: 汉诺塔问题
    原文地址: https://blog.csdn.net/weixin_38331049/article/details/88696619
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞