算法设计与分析--贪心算法课本练习和回溯法进阶练习

 

目录

贪心算法课本练习

第1关:单源最短路径问题

回溯法进阶练习

先粗略的介绍一下回溯法:

回溯法的特征:

递归回溯一般算法框架:

第1关:子集和问题

         第2关:最小长度圆排列

分析:计算该排列每个圆的圆心坐标

第3关:工作分配问题


贪心算法课本练习


第1关:单源最短路径问题

任务描述

本关任务:编写程序采用贪心算法计算单源最短路径。

相关知识

为了完成本关任务,你需要掌握:1.如何使用邻接矩阵表示图,2.如何设计贪心选择策略将问题规模逐渐变小来解决单源最短路径问题。

编程要求

单独设计Dijkstra算法(函数)来求解单源最短路径问题,在Main函数中初始化一个带权有向图的临界矩阵,并调用函数Dijkstra()求解并输出结果。说明,Main函数已经给出初始化的邻接矩阵c[][],为了便于计算,将邻接矩阵c[][]的0行和0列初始化为0,矩阵从c[1][1]到c[n][n]区域表达顶点v1、v2、...vn的邻接关系。

测试说明

平台会对你编写的代码进行测试:

测试输入:Main函数已经初始化邻接矩阵;

预期输出: 输出结果,按照如下示例格式:

0 10 50 30 60 
2<-1
3<-4<-1
4<-1
5<-3<-4<-1
其中,第一行表示顶点v1分别到v1、v2、v3、v4、v5的单源最短路径长度,v1到自身路径长度为0。第2行表示v1到v2的最短路径,第3行表示v1到v3的最短路径,第4行表示v1到v4的最短路径,第5行表示v1到v5的最短路径。

分析:

Dijkstra的主要思想:

设置顶点集合S,并不断的做贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短长度已知。初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路径称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到s中,同时对数组dist做出必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其他顶点之间的最短路径长度。

c[i][j]表示边(i,j)的权。prev[i]记录的是从源到顶点i的最短路径上i的前一个顶点。dist[i]表示当前从源到顶点i的最短特殊路径长度。

 代码如下:

#include<iostream>
#include<sstream>
#include<string>
using namespace std;
#define maxint 9999

template<class Type>
void Dijkstra(int n, int v, Type dist[], int prev[], Type c[][6])
{
	//初始化操作 
	bool s[6];//表示点是否在集合中 
	for (int i = 1; i <= n; i++)
	{
		dist[i] = c[v][i];
		s[i] = false;//初始化时,除了v外所有点均不在s集合中 
		//判断结点是否可达 ,不可达前驱结点设置为0,可达前驱结点为源点 
		if (dist[i] == maxint)
		{
			prev[i] = 0;
		}
		else
		{
			prev[i] = v;
		}
	}
	dist[v] = 0; s[v] = true;//设置源点V到自身的距离为0,将v加入到S顶点集合中
    /*初始化完成*/
    //
	for (int i = 1; i < n; i++)
	{
		int temp = maxint;
		int u = v;
		for (int j = 1; j <= n; j++)//求离出发点最近的一个顶点 
		{
			if ((!s[j]) && (dist[j] < temp))//点j在s中且距离出发点最近
			{
				u = j;
				temp = dist[j];
			}
			 
		}
		s[u] = true;//将该点加入s
		for (int j = 1; j <= n; j++)//s集合加入新点的时候需要更新dist[]和prev[] 
		{
			if ((!s[j]) && (c[u][j] < maxint))//如果j点不在s中,且新点与j点相邻 
			{
				Type newdist = dist[u] + c[u][j];//新点到v的距离+新点到j的距离 
				if (newdist < dist[j])//判断距离是不是需要更新
				{
					dist[j] = newdist;
					prev[j] = u;//新点成了j的前驱结点,表示此时从v到j点经过u距离最短 
				}
			}
		}
	}

    //输出结果
	for (int i = v; i <= n; i++)
	{
		cout << dist[i] << " ";
	}
	cout << endl;
	for (int i = 2; i <= n; i++)
	{
		cout << i;
		int j = i;
		while (j != 1)
		{
			cout << "<-" << prev[j];
			j = prev[j];
		}
		cout << endl;
	}
}
int  main()
{
	int c[6][6] = { {0},{0,0,10,maxint,30,100},
				 {0,maxint,0,50,max
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值