各算法思想总结

数据结构与算法归纳总结

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+Δ ) 
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Kruskal算法是一种用于求解最小生成树的贪心算法,它的基本思想是:按照边权从小到大的顺序,逐个加入到生成树,如果加入该边会形成环,则不加入该边,直到生成树有n-1条边为止。具体实现过程如下: 1. 将所有边按照边权从小到大排序; 2. 依次枚举每条边,如果该边的两个端点在同一个集合,则不加入该边,否则加入该边,并将两个端点所在的集合合并成一个集合; 3. 直到生成树的边数为n-1时停止。 Kruskal算法的时间复杂度为O(mlogm),其m为边数。它的优点是简单易实现,且能够在保证最小生成树的情况下尽可能地保证连通性。 ### 回答2: Kruskal算法是一种用于解决最小生成树问题的贪心算法。它的思想是从图的所有边选取权重最小的边,并且保证边的选取不会构成一个环,逐步构建最小生成树。 具体实现Kruskal算法的步骤如下: 1. 初始化一个空的最小生成树MST和一个边集合E,边集合E包含图的所有边,并按照权重从小到大排序。 2. 从E选择权重最小的边,并将其从边集合E移除。 3. 如果选择的边不会与MST的边构成环路,将其加入MST。 4. 重复步骤2和3,直到MST包含了图的所有顶点。 5. 最终得到的MST即为图的最小生成树。 Kruskal算法的关键在于如何判断选取的边是否会构成环路。为了实现这一点,可以使用并查集数据结构来记录每个顶点所属的连通分量,检查是否存在连通分量的根节点相同的两个顶点,如果存在,则选取的边会构成环路。 由于Kruskal算法每次选择权重最小的边,且这些边不会构成环路,所以最终得到的最小生成树肯定是具有最小权重的树。因此,Kruskal算法可以高效地找到图的最小生成树。 总的来说,Kruskal算法是一种简单且高效的贪心算法,用于解决最小生成树问题。它的核心思想是选择权重最小的边,并保证选取的边不会构成环路,从而逐步构建最小生成树。 ### 回答3: Kruskal算法是一种用于构建最小生成树的贪心算法。其思想是通过不断选择边,将边逐渐添加至最小生成树,直到最小生成树的边数达到图的节点数减一为止。 具体来说,Kruskal算法的步骤如下: 1. 将图的所有边按照权重从小到大进行排序。 2. 创建一个空的最小生成树。 3. 循环遍历排序后的边,每次选择权重最小的边。 4. 判断选择的边是否存在于最小生成树。如果不存在,将其加入最小生成树;如果存在,则舍弃该边。 5. 重复步骤3和步骤4,直到最小生成树的边数达到图的节点数减一。 Kruskal算法的核心思想是通过选择边来逐步扩展最小生成树,并且保证选取的边不形成环路。在每次选择边时,判断是否会导致环路的出现,可以使用并查集进行高效的判断。只有当选取的边不会导致环路时,才将其加入最小生成树。 Kruskal算法的时间复杂度取决于排序边的时间复杂度,通常使用快速排序等时间复杂度为O(ElogE)的排序算法。其E为边的数量。而由于要判断选择的边是否会导致环路,需要使用并查集来进行高效的判断,其时间复杂度为O(VlogV),其V为图的节点数。 总结来说,Kruskal算法是一种贪心算法,通过选择权重最小的边来逐步构建最小生成树。它的思想简单且易于理解,适用于性能要求不太苛刻的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值