0
点赞
收藏
分享

微信扫一扫

JavaScript或其他编程语言中关于函数的各种高级特性和设计模式

  前言:

本系列是学习了董晓老师所讲的知识点做的笔记

董晓算法的个人空间-董晓算法个人主页-哔哩哔哩视频 (bilibili.com)

 动态规划系列(还没学完)

【董晓算法】动态规划之线性DP问题-CSDN博客

【董晓算法】动态规划之背包DP问题(2024.5.11)-CSDN博客

【董晓算法】动态规划之背包DP与树形DP-CSDN博客

字符串系列()

【董晓算法】竞赛常用知识之字符串1-CSDN博客

【董晓算法】竞赛常用知识之字符串2-CSDN博客

数据结构系列(未学完)

【董晓算法】竞赛常用知识点之数据结构1-CSDN博客

搜索系列

[董晓算法]搜索相关题目及模板-CSDN博客

拓扑排序

 Kahn(卡恩)算法(这个好理解)


bool toposort(){
  queue<int> q;
  for(int i = 1; i <= n; i++)
    if(din[i]==0) q.push(i);
  while(q.size()){
    int x=q.front(); q.pop();
    tp.push_back(x);
    for(auto y : e[x]){
      if(--din[y]==0) q.push(y);
    }
  }
  return tp.size() == n;
}
int main(){
  cin >> n >> m;
  for(int i=0; i<m; i++){
    cin >> a >> b;
    e[a].push_back(b);
    din[b]++;
  }
  if(!toposort()) puts("-1");
  else for(auto x:tp)printf("%d ",x);
  return 0;
}

 DFS 算法

vector<int> e[N], tp;
int c[N]; //染色数组

bool dfs(int x){
  c[x] = -1;
  for(int y : e[x]){
    if(c[y]<0)return 0; //有环 
    else if(!c[y])
      if(!dfs(y))return 0;
  }
  c[x] = 1;
  tp.push_back(x);
  return 1;
}
bool toposort(){
  memset(c, 0, sizeof(c));
  for(int x = 1; x <= n; x++)
    if(!c[x])
      if(!dfs(x))return 0;
  reverse(tp.begin(),tp.end());
  return 1;
}

最短路

Dijkstra算法

每次

Dijkstra(迪杰斯特拉)算法是基于贪心思想的单源最短路算法

暴力法

添边
struct edge { int v, w; };
vector<edge>e[N];
for (int i = 0; i < m; i++) {
	cin >> a >> b >> c;
    e[a].push_back({ b,c });
}
核心代码
void dijkstra(int s) {
	for (int i = 0; i <= n; i++) d[i] = inf;
	d[s] = 0;//原点设为0
	for (int i = 1; i < n; i++) {
		int u = 0;
		for (int j = 1; j <= n; j++)//枚举每一个点
			if (!vis[j] && d[j] < d[u]) u = j;
		vis[u] = 1;//标记
		for (auto ed : e[u]) {
			int v = ed.v, w = ed.w;
			if (d[v] > d[u] + w) {
				d[v] = d[u] + w;
			}
		}
	}
}
代码 
struct edge { int v, w; };
vector<edge>e[N];
int d[N], vis[N];
void dijkstra(int s) {
	for (int i = 0; i <= n; i++) d[i] = inf;
	d[s] = 0;//原点设为0
	for (int i = 1; i < n; i++) {
		int u = 0;
		for (int j = 1; j <= n; j++)//枚举每一个点
			if (!vis[j] && d[j] < d[u]) u = j;
		vis[u] = 1;//标记
		for (auto ed : e[u]) {
			int v = ed.v, w = ed.w;
			if (d[v] > d[u] + w) {
				d[v] = d[u] + w;
			}
		}
	}
}
int main() {
	cin >> n >> m >> s;
	for (int i = 0; i < m; i++) {
		cin >> a >> b >> c;
		e[a].push_back({ b,c });
	}
	dijkstra(s);
	for (int i = 1; i <= n; i++)
		printf("%d ", d[i]);
	return 0;
}

 Heap-Dijkstra堆优化版

用优先队列维护被更新的点的集合O(mlogm)

 创建一个pair类型的大根堆q{-距离,点),把距离取负值,距离最小的元素在堆顶

void dijkstra(int s) {
	for (int i = 0; i <= n; i++) d[i] = inf;
	d[s] = 0;//原点设为0  
	q.push({0, s});
	/*for (int i = 1; i < n; i++) {
		int u = 0;
		for (int j = 1; j <= n; j++)//枚举每一个点
			if (!vis[j] && d[j] < d[u]) u = j;
		vis[u] = 1;//标记
		for (auto ed : e[u]) {
			int v = ed.v, w = ed.w;
			if (d[v] > d[u] + w) {
				d[v] = d[u] + w;
			}
		}
	}*/
	while (q.size()) {
		auto t = q.top(); q.pop();
		int u = t.second;
		if (vis[u]) continue;
		vis[u] = 1;
		for (auto ed : e[u]) {
			int v = ed.v, w = ed.w;
			if (d[v] > d[u] + w) {
				d[v] = d[u] + w;
				q.push({-d[v], v});
			}
		}
	}
}

路径记录与递归输出

红颜色为与上述堆化版不同处

 Bellman-Ford 算法

 P3385 【模板】负环 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

bool bellmanford() {
    memset(d, inf, sizeof d); d[s] = 0;//起点到起点距离设为0
    bool flag; //是否松弛
    for (int i = 1; i <= n; i++) { //n轮
        flag = false;
        for (int u = 1; u <= n; u++) { //n个点
            if (d[u] == inf)continue;
            for (auto ed:e[u]) {
                int v = ed.v,w=ed.w;
                if (d[v] > d[u] + w[j]) {
                    d[v] = d[u] + w[j];
                    flag = true;
                }
            }
        }
        if (!flag)break;
    }
    return flag; //有负环
}

Bellman-Ford 算法的优化-SPFA

bool spfa(int s) { 
    memset(d, inf, sizeof d);
    d[1] = 0, vis[1] = 1;  q.push(1);
    while (q.size()) {
        int u = q.front(); q.pop(); vis[u] = 0;
        for (auto ed:e[u]) {
            int v = ed.v, w = ed.w;
            if (d[v] > d[u] + w[i]) {
                d[v] = d[u] + w[i];
                cnt[v] = cnt[u] + 1;//记录边数
                if (cnt[v] >= n)return true;//有负环
                if (!vis[v])q.push(v), vis[v] = 1;
            }
        }
    }
    return false;
}

算法对比

Floyd算法

void floyd(){
  for(int k=1; k<=n; k++)
    for(int i=1; i<=n; i++)
      for(int j=1; j<=n; j++)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}

路径的记录与递归输出

和二叉树的遍历方式类似

对比 

举报

相关推荐

0 条评论