筆記:五大常用算法

貪婪算法,動態規劃算法,分治算法,回溯算法,分支限界算法

貪心算法

單源最短路

 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;
}

 

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