有营养的算法笔记

Posted 一个山里的少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有营养的算法笔记相关的知识,希望对你有一定的参考价值。

有营养的算法比较二

最短距离

1.本题为某公司的笔试题,所以没有这个测试链接。在这里只给出代码和思路。
2.题目描述

int n, int[][] roads, int x, int y,n表示城市数量,城市编号0~n-1
roads[i][j] == distance,表示城市i到城市j距离为distance(无向图)
求城市x到城市y的最短距离。注意本题可能会出现[1,5,2],[1,5,6].即1号城市到5号城市的距离为2,和1号城市到5号城市的距离为6.

3.解题思路

暴力解法:
1.先生成邻接表代表某个节点到某个节点距离为多少(这个需要取最小值因为题目的输入犯贱)
2.定义visit数组用来记录每个点是访问过还是没有访问过。
3.深度优先遍历从x节点开始遍历其所能到达的所有节点,从所有的可能性当中取一个距离最小的即可。

4.对应代码

int minDistance1(vector<vector<int>>& road, int n, int x, int y)
	
		//注意城市的下标是从1位置开始的0位置丢弃不用
		vector<vector<int>>Map(n + 1, vector<int>(n + 1, INT_MAX));
		//一开始设计为整型最大代表不可达
		for (int i = 0; i < n; i++)
		
			//这是因为输入犯贱
		    //1 2 10
			//1 2 9  有可能有这样的输入
			Map[road[i][0]][road[i][1]] = min(Map[road[i][0]][road[i][1]], road[i][2]);
			Map[road[i][1]][road[i][0]] = min(Map[road[i][1]][road[i][0]], road[i][2]);
		
		//生成邻接表,Map[i][j]的含义代表 i到j的距离为d
		vector<bool>visit(n+ 1);
		return process(Map, x, y, visit, n);
	
	//从cur这个节点到target这个节点的最小距离是多少
	int process(vector<vector<int>>& Map, int cur, int target, vector<bool>& visit,int n)
	
		//已经访问过了
		if (visit[cur]) 
			return INT_MAX;
		
		if (cur == target) //找到x这个节点了
			return 0;
		
		visit[cur] = true;
		int ans = INT_MAX;
		for (int next = 1; next <= n; next++)
		
			//如果不是自己并且这个点可达并且没有访问过
			if (next != cur && Map[cur][next] != INT_MAX && !visit[next]) 
				int ret = process(Map, next, target, visit, n);//遍历其可达的节点
				if (ret != INT_MAX) //说明可以到达ret
					ans = min(ans, ret+Map[cur][next]);
				
			
		
		visit[cur] = false;
		return ans;

	

但是这样的方式是最暴力的所有节点都搞一遍时间复杂都有点高。下面我们来看看迪结特斯拉算法怎么来解这个题
1.第一步和暴力解一样需要生成邻接表,并且需要求这个最小值这一步还是不变的
2.准备一个优先级对象小根堆和一个visit数组标记某个节点是否从堆中弹出过,如果已经在堆当中弹出过再次弹出的时候直接忽略调因为第一次弹出的距离是最小的。
3.一开始先将x这个节点加入到优先级队列当中加入的形式为Node类型,Node当中有这个路径和城市的编号。x到x的距离为0所有pathSum为0加入到优先级队列当中,进入队列当中后每次在弹出一个看是否来到y了,是直接返回路径和,不是开始遍历当前节点可达的城市并且没有访问过将其加入到队列当中。

下面我们来看看代码如何来实现

	int minDistance2(vector<vector<int>>& road, int n, int x, int y)
	
		vector<vector<int>>Map(n + 1, vector<int>(n + 1, INT_MAX));
		//一开始设计为整型最大代表不可达
		for (int i = 0; i < n; i++)
		
			//这是因为输入犯贱
			//1 2 10
			//1 2 9  有可能有这样的输入
			Map[road[i][0]][road[i][1]] = min(Map[road[i][0]][road[i][1]], road[i][2]);
			Map[road[i][1]][road[i][0]] = min(Map[road[i][1]][road[i][0]], road[i][2]);
		
		vector<bool>visit(n + 1);
		auto cmp = [&](Node& a, Node& b) return a.pathSum > b.pathSum; ;
		priority_queue <Node, vector<Node>, decltype(cmp)>minHeap(cmp);
		//小根堆
		minHeap.push(Node(x,0));//x到x的距离为0
		while (!minHeap.empty())
		
			auto node = minHeap.top();
			minHeap.pop();
			//已经弹出过的节点不在弹出
			if (visit[node.city] == true) 
				continue;
			
			if (node.city == y) 
				return node.pathSum;
			
			visit[node.city] = true;//当前这个节点已经被访问过了
			for (int next = 1; next <= n; next++)
			
				
				if (next != node.city && !visit[next] && Map[node.city][next] != INT_MAX) 
					minHeap.push(Node(next,node.pathSum + Map[node.city][next]));
				
			
		
		return INT_MAX;//x到y不可达
	

对应总代码包含测试代码

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
/*
int n, int[][] roads, int x, int y
n表示城市数量,城市编号0~n-1
roads[i][j] == distance,表示城市i到城市j距离为distance(无向图)
求城市x到城市y的最短距离
*/
//d算法的适用条件:1.这个图一定是有向图。2:所有的边没有负数


/*
* 牛客网有测试链接名字叫做单源最段路径
*/
class Soulution

public:
	// 当前来到的Node,注意这不是城市的意思,这是就是一个普通的封装类
	// Node封装了,当前来到的城市是什么,以及,从源出发点到这个城市的路径和是多少?
	struct Node
	
		Node(int c,int p)
			:pathSum(p)
			,city(c)
		
		int pathSum;
		int city;
	;
	int minDistance1(vector<vector<int>>& road, int n, int x, int y)
	
		//注意城市的下标是从1位置开始的0位置丢弃不用
		vector<vector<int>>Map(n + 1, vector<int>(n + 1, INT_MAX));
		//一开始设计为整型最大代表不可达
		for (int i = 0; i < n; i++)
		
			//这是因为输入犯贱
		    //1 2 10
			//1 2 9  有可能有这样的输入
			Map[road[i][0]][road[i][1]] = min(Map[road[i][0]][road[i][1]], road[i][2]);
			Map[road[i][1]][road[i][0]] = min(Map[road[i][1]][road[i][0]], road[i][2]);
		
		//生成邻接表,Map[i][j]的含义代表 i到j的距离为d
		vector<bool>visit(n+ 1);
		return process(Map, x, y, visit, n);
	
	//从cur这个节点到target这个节点的最小距离是多少
	int process(vector<vector<int>>& Map, int cur, int target, vector<bool>& visit,int n)
	
		//已经访问过了
		if (visit[cur]) 
			return INT_MAX;
		
		if (cur == target) //找到x这个节点了
			return 0;
		
		visit[cur] = true;
		int ans = INT_MAX;
		for (int next = 1; next <= n; next++)
		
			//如果不是自己并且这个点可达并且没有访问过
			if (next != cur && Map[cur][next] != INT_MAX && !visit[next]) 
				int ret = process(Map, next, target, visit, n);//遍历其可达的节点
				if (ret != INT_MAX) //说明可以到达ret
					ans = min(ans, ret+Map[cur][next]);
				
			
		
		visit[cur] = false;
		return ans;

	
	int minDistance2(vector<vector<int>>& road, int n, int x, int y)
	
		vector<vector<int>>Map(n + 1, vector<int>(n + 1, INT_MAX));
		//一开始设计为整型最大代表不可达
		for (int i = 0; i < n; i++)
		
			//这是因为输入犯贱
			//1 2 10
			//1 2 9  有可能有这样的输入
			Map[road[i][0]][road[i][1]] = min(Map[road[i][0]][road[i][1]], road[i][2]);
			Map[road[i][1]][road[i][0]] = min(Map[road[i][1]][road[i][0]], road[i][2]);
		
		vector<bool>visit(n + 1);
		auto cmp = [&](Node& a, Node& b) return a.pathSum > b.pathSum; ;
		priority_queue <Node, vector<Node>, decltype(cmp)>minHeap(cmp);
		//小根堆
		minHeap.push(Node(x,0));//x到x的距离为0
		while (!minHeap.empty())
		
			auto node = minHeap.top();
			minHeap.pop();
			//已经弹出过的节点不在弹出
			if (visit[node.city] == true) 
				continue;
			
			if (node.city == y) 
				return node.pathSum;
			
			visit[node.city] = true;//当前这个节点已经被访问过了
			for (int next = 1; next <= n; next++)
			
				
				if (next != node.city && !visit[next] && Map[node.city][next] != INT_MAX) 
					minHeap.push(Node(next,node.pathSum + Map[node.city][next]));
				
			
		
		return INT_MAX;//x到y不可达
	
	
;

vector<vector<int>>getRandom(int n, int v, int d)

	vector<vector<int>>Map;
	for (int i = 0; i < n; i++)
	
		int x = rand() % v + 1;
		int y = rand() % v + 1;
		int distance = rand() % d;
		Map.push_back( x,y,distance );
	
	return Map;

int main()

	srand(time(0));
	int times = 1000;
	int cityMax = 16;
	int pathMax = 30;
	for (int i = 0; i < times; i++)
	
		int n = rand() % cityMax + 1;
		int m = rand() % 100+n;
		int x = rand() % n + 1;
		int y = rand() % n+ 1;
	
		vector<vector<int>>Map = getRandom(m, n, pathMax);

		int ans1 = Soulution().minDistance1(Map,n,x,y);
		int ans2 = Soulution().minDistance2(Map,n, x,y);
		if (ans1 != ans2) 
		
			cout << ans1 << ":" << ans2 << endl;
			cout << "错了" << endl;
			return 0;
		
	
	cout << "对了" << endl;
	return 0;

下面我们还可以看看牛客网上的一道题来验证这道题的正确性

1.对应牛客网链接

单源最短路径

2.题目描述

3.解题思路
这个题其实就是上面那个题的弱化版本,这里变成了有效图只要拿上面那个代码给一下下就可以了,非常的简单在这里就只给出代码不做过多解释了。

4.对应代码


class Solution 
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int 顶点数
     * @param m int 边数
     * @param graph intvector<vector<>> 一维3个数据,表示顶点到另外一个顶点的边长度是多少​
     * @return int
     */
     struct Node
     
        Node(int c,int p)
        :pathSum(p),city(c)
        
        int pathSum;
        int city;
     ;
    int findShortestPath(int n, int m, vector<vector<int> >& graph) 
        // write code here
        vector<vector水的化学与营养 笔记

水的化学与营养 笔记

脂类的化学与营养 笔记

脂类的化学与营养 笔记

碳水化合物的化学与营养 笔记

碳水化合物的化学与营养 笔记