贪心算法--及其典型算法

贪心算法思想

局部最优,只图眼前利益,但是局部最优之和一般不会是全局最优,但也不一定,比如最小生成树:prim和Kruscal算法还有最短路径迪杰斯特拉,都是超级优秀的贪心算法的应用。

还有分饼干问题以及0-1背包问题,都是想着局部最优,在0-1背包问题中,想着重量最优先活着价值最优先往往都得不到全局最优解,但是价值率最优的话可以达到,通常情况下。

(1)Prim算法:

注意,这里与图不一样的地方就是增加了一个结构closedge,去保存V中每个点与与已经选择的U中点之间的最小距离以及与U中那个点相连。但是我把它结构直接变换成为Graph里的vexs数组了,嘿嘿

题目:
假设有A,B,C,D,E 5个村庄要修路使每个村子都有路连接(A->B->C也算A,C相连),但是要修路的总长度最小.
在这里插入图片描述

#include<stdlib.h>
#include<iostream>
#include<math.h>
#include<string>
using namespace std;
#define MAXNUM 100
//假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
//最小生成树问题, 
int sum = 0;

typedef struct   //在prim中特存的
{
    
    
	char data;
	int adjvex;
	int lowcost;
}Closedge[MAXNUM];

typedef struct AMGraph
{
    
    
	int arcs[MAXNUM][MAXNUM];
	Closedge closedge;
	int arcnum;
	int vexnum;
}AMGraph;


int AMLocate(AMGraph* Graph, char n)
{
    
    
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (n == Graph->closedge[i].data)
		{
    
    
			return i;
			break;
		}
	}
	return -1;
}

void CreatGraph(AMGraph* Graph)
{
    
    
	cout << "请输入顶点数、边数:" << endl;
	cin >> Graph->vexnum >> Graph->arcnum;
	cout << "请输入顶点的值" << endl;
	for (int i = 0; i < Graph->vexnum; i++) 
	{
    
    
		cin >> Graph->closedge[i].data;
	}
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		for (int j = 0; j < Graph->vexnum; j++)
		{
    
    
			Graph->arcs[i][j] = MAXNUM;
    	}
	}
	cout << "请依次输入各个边的顶点以及值" << endl;
	for (int i = 0; i < Graph->arcnum; i++)
	{
    
    
		char x1, x2;
		int dis, n, m;
		cin >> x1 >> x2 >> dis;
		n = AMLocate(Graph, x1);
		m = AMLocate(Graph, x2);
		Graph->arcs[n][m] = dis;
		Graph->arcs[m][n] = dis;
	}
}

int fingMin(AMGraph* Graph)
{
    
    
	int min, temp = 0;
	min = MAXNUM;
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (Graph->closedge[i].lowcost != 0 && Graph->closedge[i].lowcost < min)
		{
    
    
			min = Graph->closedge[i].lowcost;
			temp = i;
		}
	}
	return temp;
}

void Updata(AMGraph* Graph,int min)
{
    
    
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (Graph->closedge[i].lowcost > Graph->arcs[min][i])
		{
    
    
			Graph->closedge[i].lowcost = Graph->arcs[min][i];
			Graph->closedge[i].adjvex = min;
		}
	}
}

void Prim(AMGraph* Graph,char sta)
{
    
    
	int start = AMLocate(Graph, sta);
	if (start != -1) //从该点开始;
	{
    
    
		for (int i = 0; i < Graph->vexnum; i++)
		{
    
    
			Graph->closedge[i].adjvex = start;
			Graph->closedge[i].lowcost = Graph->arcs[start][i];
		}
		Graph->closedge[start].lowcost = 0;
		sum++;
		while (sum < Graph->vexnum)
		{
    
    
			int min = fingMin(Graph);
			int u0, v0;
			u0 = Graph->closedge[min].adjvex;
			v0 = min;
			cout << Graph->closedge[u0].data << "-->" << Graph->closedge[v0].data << endl;
			Graph->closedge[min].lowcost = 0;
			sum++;
			Updata(Graph, min);
		}
	}
}

int main()
{
    
    
	AMGraph* Graph = new AMGraph;
	CreatGraph(Graph);
	// 假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
	char start = 'A';
	Prim(Graph, start);
	return 0;
}

结果:
在这里插入图片描述

(2)Kruscal算法:

跟上面同样的题目!

写这个算法的时候,自己由于大意,找了很久错误,最后发现复制的时候老是忘记改掉该改的值,很不好的习惯,还有就是复制运算=老是写成==,最后就是这个问题增加了一个辅助的数据结构是Edges,描述每一条边,因为虽然找的时候是按边从小到大找,但是会存在变=边的值比较小但是加入后形成环的现象,所以需要再加一个数组表示每个顶点在哪个连通分量中,相同连通分量的不可以加入了,说明他们已经在了。

#include<stdlib.h>
#include<iostream>
#include<math.h>
#include<string>
using namespace std;
#define MAXNUM 100
//假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
//最小生成树问题, 
int sum = 0;
int VesSet[MAXNUM];

typedef struct   //在prim中特存的
{
    
    
	char data;
	int adjvex;
	int lowcost;
}Closedge[MAXNUM];

typedef struct Edges
{
    
    
	int Head;
	int Tail;
	int lowcost;
}Edges,edge;

Edges* Edge;

typedef struct AMGraph
{
    
    
	int arcs[MAXNUM][MAXNUM];
	Closedge closedge;
	int arcnum;
	int vexnum;
}AMGraph;


int AMLocate(AMGraph* Graph, char n)
{
    
    
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (n == Graph->closedge[i].data)
		{
    
    
			return i;
			break;
		}
	}
	return -1;
}


void CreatGraph(AMGraph* Graph)
{
    
    
	cout << "请输入顶点数、边数:" << endl;
	cin >> Graph->vexnum >> Graph->arcnum;
	cout << "请输入顶点的值" << endl;
	for (int i = 0; i < Graph->vexnum; i++) 
	{
    
    
		cin >> Graph->closedge[i].data;
		VesSet[i] = i;
	}
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		for (int j = 0; j < Graph->vexnum; j++)
		{
    
    
			Graph->arcs[i][j] = MAXNUM;
    	}
	}
	cout << "请依次输入各个边的顶点以及值" << endl;
	Edge = new Edges[Graph->arcnum + 1];
	for (int i = 0; i < Graph->arcnum; i++)
	{
    
    
		char x1, x2;
		int dis, n, m;
		cin >> x1 >> x2 >> dis;
		n = AMLocate(Graph, x1);
		m = AMLocate(Graph, x2);
		Graph->arcs[n][m] = dis;
		Graph->arcs[m][n] = dis;
		Edge[i].Head = n;
		Edge[i].Tail = m;
		Edge[i].lowcost = dis;
	}
}

int pivoky(Edges* Edge,int low,int high)
{
    
    
	int pivock = Edge[low].lowcost;
	Edges temp = Edge[low];
	while (low < high)
	{
    
    
		while (low < high && Edge[high].lowcost >= pivock)
			high--;
		Edge[low] = Edge[high];
		while (low < high && Edge[low].lowcost <= pivock)
			low++;
		Edge[high] = Edge[low];
	}
	Edge[high] = temp;
	return high;
}

void QuickSort(Edges* Edge, int low, int high)
{
    
    
	if (low < high)
	{
    
    
		int pivocy = pivoky(Edge, low, high);
		QuickSort(Edge, low, pivocy - 1);
		QuickSort(Edge, pivocy + 1, high);
	}
}

void Kruscal(AMGraph* Graph)
{
    
    
	QuickSort(Edge, 0, Graph->arcnum - 1);
	int u0, v0;
	for (int i = 0; i < Graph->arcnum; i++)
	{
    
    
		u0 = Edge[i].Head;
		v0 = Edge[i].Tail;
		int set = VesSet[v0];
		if (VesSet[u0] != VesSet[v0])
		{
    
    
			cout << Graph->closedge[u0].data << "-->" << Graph->closedge[v0].data << endl;
			for (int j = 0; j < Graph->vexnum; j++)
			{
    
    
				if (VesSet[j] == set)
					VesSet[j] = VesSet[u0];    //合并分量
			}
		}
	}
}


int main()
{
    
    
	AMGraph* Graph = new AMGraph;
	CreatGraph(Graph);
	// 假设有A, B, C, D, E 5个村庄要修路使每个村子都有路连接(A->B->C也算A, C相连), 但是要修路的总长度最小.
	//char start = 'A';
	//Prim(Graph, start);
	Kruscal(Graph);

	return 0;
}

(3)Dijkstra算法:

还是最初的那一题。
总结:
由于太累了,输出就简化一下,倒着输出了。
这个算法写出来之后给我的感觉就是,不可以一味地凭着感觉来,我在最初将每次计算出最短路径的点的D[i]的值直接置为了0,想让它代替S的作用,但是实际上并不行,与Prim算法不同的是,在这里强调从某个点出发到其余各点的最短路径,故每次计算更新时都需要用到已经求得的最短路径,如果将它们的D[i]置为0,则会导致整个算法错误。
这些算法看着跟自己敲出来还是不一样的,所以自己多想。

#include<stdlib.h>
#include<iostream>
#include<math.h>
#include<string>
using namespace std;
#define MAXNUM 100
int D[MAXNUM];
int path[MAXNUM];
bool S[MAXNUM];

typedef struct   //在prim中特存的
{
    
    
	char data;
	int adjvex;
	int lowcost;
}vexsnumal;

typedef struct AMGraph
{
    
    
	int arcs[MAXNUM][MAXNUM];
	char vexs[MAXNUM];
	int arcnum;
	int vexnum;
}AMGraph;

int AMLocate(AMGraph* Graph, char n)
{
    
    
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (n == Graph->vexs[i])
		{
    
    
			return i;
			break;
		}
	}
	return -1;
}

void CreatGraph(AMGraph* Graph)
{
    
    
	cout << "请输入顶点数、边数:" << endl;
	cin >> Graph->vexnum >> Graph->arcnum;
	cout << "请输入顶点的值" << endl;
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		cin >> Graph->vexs[i];
		S[i] = false;
	}
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		for (int j = 0; j < Graph->vexnum; j++)
		{
    
    
			Graph->arcs[i][j] = MAXNUM;
		}
	}
	cout << "请依次输入各个边的顶点以及值" << endl;
	for (int i = 0; i < Graph->arcnum; i++)
	{
    
    
		char x1, x2;
		int dis, n, m;
		cin >> x1 >> x2 >> dis;
		n = AMLocate(Graph, x1);
		m = AMLocate(Graph, x2);
		Graph->arcs[n][m] = dis;
		Graph->arcs[m][n] = dis;
	}
}

int fingMin(AMGraph* Graph)
{
    
    
	int min, temp = 0;
	min = MAXNUM;
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (min > D[i] && S[i] !=true)
		{
    
    
			min = D[i];
			temp = i;
		}
	}
	return temp;
}

void Update(AMGraph* Graph,int min)
{
    
    
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (D[min] + Graph->arcs[i][min] < D[i])
		{
    
    
			D[i] = D[min] + Graph->arcs[i][min];
			path[i] = min;
		}
	}
}

void Dijkstra(AMGraph *Graph,char sta)
{
    
    
	int sum = 1;
	int start = AMLocate(Graph, sta);
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		D[i] = Graph->arcs[start][i];
		if (Graph->arcs[i][start] != MAXNUM)
			path[i] = start;
		else
			path[i] = -1;
	}
	D[start] = 0;
	S[start] = true;
	path[start] = 0;
	//cout << sta << "-->";
	while (sum < Graph->vexnum)
	{
    
    
		int min = fingMin(Graph);
		S[min] = true;
		Update(Graph,min);
		sum++;
	}
}

int main()
{
    
    
	AMGraph* Graph = new AMGraph;
	CreatGraph(Graph);
	char sta = 'A';
	int start = AMLocate(Graph,sta);
	Dijkstra(Graph, sta);
	for (int i = 0; i < Graph->vexnum; i++)
	{
    
    
		if (Graph->vexs[i] != sta)
		{
    
    
			cout << Graph->vexs[i] << "<--";
			int pre = path[i];
			while (pre != 0)
			{
    
    
				cout << Graph->vexs[pre] << "<--";
				pre = path[pre];
			}
			cout << Graph->vexs[start] << endl;
		}
	}
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43978754/article/details/115052072