笔记:五大常用算法

贪婪算法,动态规划算法,分治算法,回溯算法,分支限界算法

贪心算法

单源最短路

 Dijkstra算法
 

最小生成树

Kruskal算法

Prim算法

https://blog.csdn.net/luoshixian099/article/details/51908175/

 

动态规划算法

任意两点间的最短路

Floyd算法

 

01揹包——m[ i ][ j ] 表示 在面对第 i 件物品,且揹包容量为  j 时所能获得的最大价值 ,不断的更新它,因为得出的之前的每一处都是那个容量的最优值,当考虑到容量增大时进行判断。

#include <iostream>
#include <cstring>
using namespace std;
const int N = 15;

int max(int a,int b)
{	return a > b ? a : b;}

int main()
{
	int v[N] = { 0,8,10,6,3,7,2 };
	int w[N] = { 0,4,6,2,2,5,1 };


	int m[N][N];//m[i][j] 表示 在面对 第i件物品,且 揹包容量为j 时所能获得的最大价值
	int n = 6, c = 12;
	memset(m, 0, sizeof(m));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			if (j >= w[i])
				m[i][j] = max(m[i - 1][j], m[i - 1][j - w[i]] + v[i]);
			//上边这一句是装第i件物品,把“装上i就满了”(m[i-1][j-w[i]])的最优价值(查之前算过的数组),在加上第i件物品的价值(v[i])
			//与上个容量的最大价值(m[i - 1][j])相比较。高者为此时最优。
			else
				m[i][j] = m[i - 1][j];
		}
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			cout << m[i][j] << ' ';
		}
		cout << endl;
	}
	return 0;
}

上方代码摘自https://blog.csdn.net/xp731574722/article/details/70766804

 

分治算法

快速排序(二分法+递归)

//快速排序
#include <stdio.h>

void swap(int a[], int i, int j)
{
	int t = a[i];
	a[i] = a[j];
	a[j] = t;
}
//二分
int partition(int a[], int p, int r)
{
	int i = p;
	int j = r + 1;
	int x = a[p];//取其中一元素当哨兵
	while (1) {
		while (i<r && a[++i]<x);	//向后找到“位置在后却大于哨兵”的元素
		while (a[--j]>x);			//向前……
		if (i >= j) break;		//当小i指针与大j指针相遇则结束本轮
		swap(a, i, j);//交换(a[i]比x大却在前,a[j]比x小却在后。交换)
	}
	swap(a, p, j);//把哨兵还回去
	return j;
}
//递归
void quicksort(int a[], int p, int r)
{	
	//如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了
	if (p<r) {
		int q = partition(a, p, r);//使用二分
		quicksort(a, p, q - 1);
		quicksort(a, q + 1, r);
	}
}

int main()
{
	int i;
	int a[12] = { 5,13,6,24,-2,8,-19,27,0,12,1,17 };

	quicksort(a, 0, 12-1);//数组名、要排序的首位置、尾位置

	for (i = 0; i<N; i++) printf("%d ", a[i]);//输出验证

	return 0;
}

 

回溯算法

迷宫可达计数(深度优先搜索)

//‎2016‎.‎7.7 ‏‎11:04:52迷宫问题、深度优先搜索计数所有可到达的格子数,helped by王星宇
#include<stdio.h>
#include<stdlib.h>
#define scanf scanf_s

int maze[5][5] = {
	0, 1, 0, 0, 0,
	0, 1, 0, 1, 0,
	0, 0, 0, 0, 0,
	0, 1, 1, 1, 0,
	0, 0, 0, 1, 0,
};
int a = 5, b = 5;//几行几列

int  dfs(int x, int y)//深度优先搜索
{
	if (x < 0 || x >= a || y < 0 || y >= b ||
		maze[x][y] == 1 || maze[x][y] == 2)
	{
		return 0;//界限、撞墙结束,且不加步数
	}
	else
	{
		maze[x][y] = 2;//此地设定为搜过,不走回头路,=====(有误:)且函数内局部改变的迷宫不影响函数外的全局迷宫

		//执行一次,显示全部迷宫
		for (int i = 0; i < a; i++, printf("\n"))
			for (int j = 0; j < b; j++)
				printf("%d ", maze[i][j]);
		printf("\n");

        //向四个方向(下、上、右、左)递归,返回累加步数
		return 1 + dfs(x + 1, y) + dfs(x - 1, y)
			+ dfs(x, y + 1) + dfs(x, y - 1);
	}
}


int main()
{
	printf("ans: %d\n", dfs(0, 0));//从0,0开始搜索

	printf("最后的可到达区域格子数:\n");//1是墙,2是走过的地方
	for (int i = 0; i < a; i++, printf("\n"))
		for (int j = 0; j < b; j++)
			printf("%d ", maze[i][j]);

	system("pause");
	return 0;
}

8皇后问题(穷举+剪枝)

https://blog.csdn.net/three_body/article/details/16361417

 

分支限界算法

迷宫最短路径(广度优先搜索)

//广度优先搜索,输出每次寻找的位置,最短到达路径是第一次找到路径的搜索层数
#include<iostream>
#include<queue>//使用队列
using namespace std;
#define scanf scanf_s

int maze[5][5] = {
	0, 1, 0, 0, 0,
	0, 1, 0, 1, 0,
	0, 0, 0, 0, 3,
	0, 1, 1, 1, 0,
	0, 0, 0, 1, 0,
};
int a = 5, b = 5;//几行几列
int dir[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };//四个遍历方向

struct position {
	int px;
	int py;
	int	lay;//层数
};
queue <position> q;

void print(int lay)
{
	printf("\n当前搜索第%d层。\n",lay);
	for (int i = 0; i < a; i++, printf("\n"))
		for (int j = 0; j < b; j++)
			printf("%d ", maze[i][j]);
}

void execute()
{	
	//取队列头,然后删除头节点=========
	int x=q.front().px;// q.front()返回队首元素的值,但不删除该元素
	int y=q.front().py;
	int layThis = q.front().lay;
	q.pop();  //删除队列首元素但不返回其值


	//判断当前节点存的位置=============
	//判断当前位置是否出界0、撞墙1、已经搜索过2
	if (x < 0 || x >= a || y < 0 || y >= b ||maze[x][y] == 1 || maze[x][y] == 2)
	{
		return ;//界限、撞墙结束,且不加步数
	}
	//判断是否在本层的此位置找到了目标
	else if (maze[x][y] == 3)
	{
		printf("找到了一个路径!!!!\n");//输出层数,就是走的最少步数
		return ;//结束
	}
	//将此节点的下层节点安排上,到队列中去=========
	else
	{
		maze[x][y] = 2;//此地设定为搜过,不走回头路
		print(layThis);//打印迷宫

		//处理完节点,将此节点的下一层节点放入队列等待处理
		//安排上,向四个方向搜索并入队列(添加新的一层)(右、左、上、下)的位置加入队列尾
		position p;
		for (int i = 0; i < 4; i++)
		{
			p.px = x + dir[i][0];
			p.py = y + dir[i][1];
			p.lay = layThis + 1;//本层节点的子节点,所以层数+1
 			q.push(p);//在队尾压入新元素 ,p为要压入的元素
		}
	}
}


void bfs(int x, int y)//广度优先搜索
{
	//先将此位置放入队列
	position p;
	p.px = x ;	p.py = y; p.lay= 0;
	q.push(p);//在队尾压入新元素 ,p为要压入的元素

	//===队列任务处理===
	//判断队列任务是否清空(清空就结束了),没清空则处理剩余的(一存整一层的,逐个清空同时尾部填入下一层的要检查的位置)
	while(!q.empty())
	{
		execute();//处理队列中的第一个,然后开始递推。
	}
}


int main()
{
	//printf("ans: %d\n", bfs(0, 0));//从0,0开始搜索

	bfs(0, 0);

	printf("\n\n最后的可到达目标路径的区域格子:\n");//1是墙,2是走过的地方
	print(-1);//此时队列没东西了……随便赋了值

	system("pause");
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章