贪心算法、DijKstra算法

贪心算法、DijKstra算法,第1张

算法设计思想:
    1.贪心/贪婪算法
    2.分而治之 --->快排 + 拓展的归并
    3.动态规划
    4.回溯        --->递归  n皇后问题
    5.分支定界

基本思想

通过作出在当前看来最优的选择(贪心选择),将原问题规模缩小,如此反复,直至得到最终解
贪心算法并非对所有问题都能得到整体最优解
贪婪算法每一步所选的结果都是局部的最优解
这么做的目的就是希望经过所有的步骤所得到的解答会是全局最优解
不过事实上的结果并不一定能达到全局最优解
贪婪算法所花的时间通常较少,且就算不是全局最优解,但最后所得结果也不会太差
贪婪准则:最小方案  最大方案  最值思想

背包问题: (货物装载问题)
给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

在选择装入背包的物品时,对每种物品i只有2种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品 i

用贪心算法解背包问题的基本步骤:
首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心选择策略,将尽可能多的单位重量(小)价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。依此策略一直地进行下去,直到背包装满为止。

最短路径问题:

从A点出发到B点,如何找出最短的路径?

2 + 1 + 6 + 1 + 2 == 12,但是 12 不是最佳选择,3 + 1 + 2 + 1 + 2 == 9,所以贪心算法得到的答案不一定是最优解

DijKstra:迪杰斯特拉算法
使用贪心算法的思想,从起点到顶点的最短路径
通过不断的新选择距离最近的顶点,来逐渐扩大最短路径权值,
直到覆盖了所有的顶点

有 5 个顶点,每个顶点之间有一个权值,选定顶点 1 作为入口,1 ~  2 的距离是 10,当前 1 ~ 3  没有直接连通,用无穷大表示,以此类推 . . . 接着扩充第 2 个顶点,做连通状态,1 ~ 2 是连通状态,2 ~ 3 也是连通状态,1 ~ 3 的距离是  10 + 50 == 60,扩充顶点 4,1 ~ 3 有一个新的距离:1 - 4 - 3 距离 50 < 60,根据最短路径原则,把 1 ~ 3 的距离更新为 50,每次保留从当前节点到另一个节点的最小距离,不断更新当前顶点与其他顶点的最短路径,最终得到:到每一个顶点的最短距离

        1        2        3        4

1              10

2                        20

3

4

[ 1 ][ 2 ] != ∞

[ 2 ][ 3 ] != ∞

1 ~ 2 是连通的状态,2 ~ 3 是连通的状态

如果当前位置的列数等于另一个位置的行数就是连通的状态,1 ~ 3 就是连通的状态

Huffman编码:

哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。
给出现频率高的字符较短的编码,出现频率较低的字符以较长的编码,可以大大缩短总码长。

数据结构 --- 哈夫曼树基础_菜徐鸭的博客-CSDN博客
前缀码
对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其它字符代码的前缀。这种编码称为前缀码。
      前缀约束:一个字符的编码必须不能是另一个编码
      的前缀,将数组以最优二叉树的方式存储。
       (规定左节点>右节点)
      算法步骤:
       step1:找出现频率最小的字符b,d。
       step2:将b,d合成一个新的子节点x1,并使f(x1)=f(b)+f(d)
       step3:在剩下的字符a,c,e和x1 按step1中方法找到两个新的子节点。直到所有的字符都包含在二叉树中。

短作业调度问题( *** 作系统的调度算法)

采用最短处理时间作业优先的贪心选择策略
可以设计出解多机调度问题的较好的近似算法。
按此策略,首先将n个作业依其所需的处理时间从大到小排序。
然后依此顺序将作业分配给空闲的处理机。
(优先队列)

迪杰斯特拉算法实现

直接用数组描述有向图

数据结构 --- 图的存储_菜徐鸭的博客-CSDN博客

#include 
#include 
#include 
#define NO 0xFFFFFF	        //用无穷大表示不连通状态
#define MAX 10		        //不能直接定义太大数组-> 堆栈溢出
//图的结构体描述
typedef struct graph 
{
	char vexs[MAX];			//顶点数组
	int vexnum;				//顶点数
	int arcnum;				//边数
	int matrix[MAX][MAX];	//权值数组
}GRAPH,*LPGRAPH;
//遍历的图 选定入口 存储每一个最短距离-> 把每一个最短距离都记录下来
void DijKstra(GRAPH map, int in, int dist[]) 
{
	int i = 0;
    //成功获取路径的标记-> 标记数目由顶点数决定
	int flag[MAX];		   
	//求出当前节点到其他节点的距离
	for (int i = 0; i < map.vexnum; i++) 
	{
        //先把所有的标记置为0
		flag[i] = 0;    
        //当前节点到其他节点距离-> 遍历第一行权值数组
		dist[i] = map.matrix[in][i];
	}
    //in进来了做标记-> 已经扩充了in顶点
	flag[in] = 1;
    //in的距离置为 0
	dist[in] = 0;		
    //求扩充一个顶点后的最短路径-> 最小值
	int min;
	int k = 0;
	int j;  
	//2.扩充顶点-> 判断连通状态-> 每次扩充顶点都是距离最小的
	//数组存储顶点从下标 0 存储
	for (i = 1; i < map.vexnum; i++)    //i = 1本质是扩充第二个顶点
	{
		min = NO;					    //不连通状态-> 假设最小值为无穷大
        //如果存在比min小的值就是连通的状态-> 遍历扩充顶点的列 看有没有连通的
		for (j = 1; j < map.vexnum; j++) 
		{
            //连通的状态判断
			if (flag[j] == 0 && dist[j] < min) 
			{
				min = dist[j];          //改变当前最小值 
				k = j;					//连通的状态
			}
		}
        //把当前标记置为1
		flag[k] = 1;
        //找以 k 为行找列是否有值-> 有值说明 i 和 j 顶点是连通的
        //如果扩充节点产生新路径的距离[k,j]的值 + 原来的距离min < 原来连通的路径dist,就需要更新dist
		for (j = 1; j < map.vexnum; j++) 
		{
            //判断访问标记是不是扩充了
			if (flag[j] == 0 && (min + map.matrix[k][j]) < dist[j]) 
			{
                //更新最短路径
				dist[j] = min + map.matrix[k][j];
			}
		}
	}
	printf("\n");
    //打印路径
	for (int i = 1; i < map.vexnum; i++) 
	{
        //从入口开始到当前顶点的最短路径
		printf("最短路径:(%c,%c)=%d\n", map.vexs[in], map.vexs[i], dist[i]);
	}

}
int main() 
{
    //创建图
	GRAPH map = { {'1','2','3','4','5'},5,7,
		{
			{NO,10,NO,30,100},
			{NO,NO,50,NO,NO},
			{NO,NO,NO,NO,10},
			{NO,NO,20,NO,60},
			{NO,NO,NO,NO,NO}
		}
	};
    //选定入口从'1'这个顶点进来,找到其他顶点的距离 0号顶点当做入口
	int in = 0;		
    //存储所有的距离
	int dist[MAX];	
	DijKstra(map, in, dist);
	return 0;
}

/*输出*/


最短路径:(1,2)=10
最短路径:(1,3)=50
最短路径:(1,4)=30
最短路径:(1,5)=60

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/707022.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-24
下一篇 2022-04-24

发表评论

登录后才能评论

评论列表(0条)

保存