当前位置: 首页 > news >正文

自用的板子(搜索与图论)

一、DFS和BFS

1、DFS:N皇后问题、树的重心

2、BFS:迷宫问题、图中点的层次

二、拓扑排序

用于解决有向图,比如某个条件是解决另外一个条件的先前条件
时间复杂度:O(V + E)

链式前向星建有向图,入点++然后跑拓扑

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int h[N], e[N], ne[N], idx;
int q[N], d[N];
int n, m;
void add(int a, int b){e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool toposort(){int hh = 0, tt = -1;for(int i = 1; i <= n; i++){if(!d[i])q[++tt] = i;}while(hh <= tt){int t = q[hh++];for(int i = h[t]; i != -1; i = ne[i]){int j = e[i];d[j]--;if(!d[j])q[++tt] = j;}}return tt == n - 1;
}
signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;memset(h, -1, sizeof(h));while(m--){int a, b; cin >> a >> b;add(a, b);d[b]++;}if(toposort()){for(int i = 0; i < n; i++)cout << q[i] << " ";}else cout << "-1" << endl;return 0;
}

三、迪杰斯特拉算法(Dijkstra)----不存在负边权

形式一:邻接矩阵存图(稠密图),时间复杂度O(n^2)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int n, m;
int g[N][N];
int dist[N];
int st[N];
int dijkstra(){memset(dist, 0x3f, sizeof(dist));dist[1] = 0;for(int i = 0; i < n; i++){int t = -1;for(int j = 1; j <= n; j++){if(!st[j] && (t == -1 || dist[t] > dist[j]))t = j;}if(t == n)break;st[t] = true;for(int j = 1; j <= n; j++){dist[j] = min(dist[j], dist[t] + g[t][j]);}}if(dist[n] == 0x3f3f3f3f)return -1;return dist[n];
}signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;memset(g, 0x3f, sizeof(g));while(m--){int a, b, c; cin >> a >> b >> c;g[a][b] = min(g[a][b], c);}int t = dijkstra();cout << t << endl;return 0;
}

形式二:堆优化的迪杰斯特拉,邻接表存图(稀疏图),时间复杂度O((m+n)logn)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 150010;
int n, m;
int h[N], e[N], ne[N], idx, w[N];
int dist[N];
bool st[N];
void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int dijkstra(){memset(dist, 0x3f, sizeof(dist));dist[1] = 0;priority_queue<PII, vector<PII>, greater<PII>>heap;heap.push({0, 1});while(heap.size()){auto t = heap.top();heap.pop();int ver = t.second, distance = t.first;if(st[ver])continue;st[ver] = true;for(int i = h[ver]; i != -1; i = ne[i]){int j = e[i];if(dist[j] > distance + w[i]){dist[j] = distance + w[i];heap.push({dist[j], j});}}}if(dist[n] == 0x3f3f3f3f)return -1;else return dist[n];
}signed main() {ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;memset(h, -1, sizeof(h));while(m--){int a, b, c; cin >> a >> b >> c;add(a, b, c);}int t = dijkstra();cout << t << endl;return 0;
}

四、贝尔曼福特算法(Bellman-ford)---解决负边权

思路:for循环n次,备份(for)所有边a,b,w表示所有a到b的边权值为w,(松弛),处理有福边权,能判断是否有负环(但是一般用spfa做)。第k次(k是步数限制)松弛:找到经过最多k条边的最短路径,通过多次松弛,算法可以逐步覆盖从起点到所有节点的所有可能路径。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 510, M = 10010;
int n, m, k;
int dist[N], backup[N];
struct Edge{int a, b, w;
}edges[M];
int bellman_ford(){memset(dist, 0x3f, sizeof(dist));dist[1] = 0;for(int i = 0; i < k; i++){memcpy(backup, dist, sizeof(dist));for(int j = 0; j < m; j++){int a = edges[j].a, b = edges[j].b, w = edges[j].w;dist[b] = min(dist[b], backup[a] + w);}}if(dist[n] > 0x3f3f3f3f / 2)return -0x3f3f3f3f;return dist[n];
}
signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m >> k;for(int i = 0; i < m; i++){cin >> edges[i].a >> edges[i].b >> edges[i].w;}int t = bellman_ford();if(t == -0x3f3f3f3f)cout << "impossible" << endl;else cout << t << endl;return 0;
}

五、SPFA算法

1、求最短路----带负边权
用队列,只要有变小就取出队头,更新t的所有出边,成功就加入队列(更新过谁就那谁出来操作)通过队列优化Bellman-Ford算法,只对距离发生变化的节点进行松弛操作

时间复杂度:最好情况O(m),最坏情况O(nm)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m;
int h[N], e[N], ne[N], idx, w[N];
int dist[N];
bool st[N];
void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int spfa(){memset(dist, 0x3f, sizeof(dist));dist[1] = 0;queue<int> q;q.push(1);st[1] = true;while(q.size()){auto t = q.front();q.pop();st[t] = false;for(int i = h[t]; i != -1; i = ne[i]){int j = e[i];if(dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];if(!st[j]){st[j] = true;q.push(j);}}}}if(dist[n] == 0x3f3f3f3f)return -0x3f3f3f3f;return dist[n];
}
signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;memset(h, -1, sizeof(h));while(m--){int a, b, c; cin >> a >> b >> c;add(a, b, c);}int t = spfa();if(t == -0x3f3f3f3f)cout << "impossible" << endl;else cout << t << endl;return 0;
}

2、判负环

思路:维护多一个cnt[x]=cnt[t] + 1的数组,如果cnt[x] >= n(本来是n-1条边)(处理的点多)说明存在负环,先全部点进队,再跑spfa,dist数组不用初始化。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2010, M = 10010;
int h[N], e[M], ne[M], idx, w[M];
int dist[N], cnt[N];
bool st[N];
int n, m;
void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
bool spfa(){queue<int> q;for(int i = 1; i <= n; i++){q.push(i);st[i] = true;}while(q.size()){int t = q.front();q.pop();st[t] = false;for(int i = h[t]; i != -1; i = ne[i]){int j = e[i];if(dist[j] > dist[t] + w[i]){dist[j] = dist[t] + w[i];cnt[j] = cnt[t] + 1;if(cnt[j] >= n)return true;if(!st[j]){q.push(j);st[j] = true;}}}}return false;
}signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;memset(h, -1, sizeof(h));while(m--){int a, b, c; cin >> a >> b >> c;add(a, b, c);}if(spfa())cout << "Yes" << endl;else cout << "No" << endl;return 0;
}

六、弗洛伊德Floyd算法

用于处理多源最短路(支持负权,不支持负环)可以检测负环

思路:逐步考虑每个节点作为中间节点,更新所有节点对之间的最短距离
时间复杂度:O(n^3)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 210, INF = 1e9;
int n, m, q;
int d[N][N];
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]);}}}
}
signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m >> q;for(int i = 1; i <= n; i++){for(int j = 1; j <= n; j++){if(i == j)d[i][j] = 0;else d[i][j] = INF;}}while(m--){int a, b, w; cin >> a >> b >> w;d[a][b] = min(d[a][b], w);}floyd();while(q--){int a, b; cin >> a >> b;if(d[a][b] > INF / 2)cout << "impossible" << endl;else cout << d[a][b] << endl;}return 0;
}

七、普里姆Prim算法

1、邻接矩阵--稠密图
思路:dist[j]是j点到最小生成树的最小距离,找未加入最小生成树的最小的节点,(找到的距离INF说明不连通),找到后加入权重总值res,再更新其他节点到生成树的最小距离
建图:邻接矩阵g[a][b] = g[b][a] = min(g[a][b], c)
时间复杂度:O(V^2)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 520, INF = 0x3f3f3f3f;
int n, m;
int g[N][N];
int dist[N];
bool st[N];
int prim(){memset(dist, 0x3f, sizeof(dist));dist[1] = 0;int res = 0;for(int i = 0; i < n; i++){int t = -1;for(int j = 1; j <= n; j++){if(!st[j] && (t == -1 || dist[t] > dist[j]))t = j;}if(i && dist[t] == INF)return INF;if(i)res += dist[t];for(int j = 1; j <= n; j++)dist[j] = min(dist[j], g[t][j]);st[t] = true;}return res;
}
signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;memset(g, 0x3f, sizeof(g));while(m--){int a, b, c; cin >> a >> b >> c;g[a][b] = g[b][a] = min(g[a][b], c);}int t = prim();if(t == INF)cout << "impossible" << endl;else cout << t << endl;return 0;
}

2、二叉堆 --稀疏图
时间复杂度:O(ElogV)

八、克鲁斯卡尔Kruskal算法

思路:结构体数组对权值排序,res存生成树总权值,cnt存边数,不在统一个集合就合并,加权值,加边数,判断cnt是否<n-1是的话就不连通,可以的话输出最小生成树总权值即可。理论上是从小到大选边
时间复杂度:O(ElogE)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int n, m;
int p[N];
struct Edge{int a, b, w;bool operator<(const Edge&W)const{return w < W.w;}
}edges[N];
int find(int x){return x == p[x] ? x : p[x] = find(p[x]);
}signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;for(int i = 0; i < m; i++){int a, b, w; cin >> a >> b >> w;edges[i] = {a, b, w};}sort(edges, edges + m);for(int i = 1; i <= n; i++)p[i] = i;int res = 0, cnt = 0;for(int i = 0; i < m; i++){int a = edges[i].a, b = edges[i].b, w = edges[i].w;a = find(a), b = find(b);if(a != b){p[a] = b;res += w;cnt++;}}if(cnt < n - 1)cout << "impossible" << endl;else cout << res << endl;return 0;
}

九、染色法

用于判断二分图

十、匈牙利算法

用于解决二分图的最大匹配

http://www.dtcms.com/a/443069.html

相关文章:

  • Process Monitor 学习笔记(5.9):Procmon 的自动化操作与命令行速查
  • 唐山网站优化中国风网页设计欣赏
  • 微网站开发需要多少费用主营网站开发
  • 网站开发者密钥sousou提交网站入口
  • 网页版qq怎么登录关键词优化的最佳方法
  • 网站备案注销怎么恢复河北省和城乡建设厅网站
  • 网站建设设计服务温州服务网站建设
  • 做交易网站需要多少钱wordpress改字体插件
  • 这样可以做网站绍兴企业网站建站模板
  • Python isinstance()和type()的区别
  • 网站备案app网站建设分金手指排名四
  • 深度剖析 C++ 之 string(上)篇
  • 前端界面不会在浏览器上显示
  • 企业网站选wordpress和织梦科技企业网站如何建设
  • OpenCoordV1.3.0正式发布,新增平面四参数转换、规范法历元转换
  • 【HarmonyOS应用】《账理通》更新啦!
  • 免费1级做爰片打网站租车做什么网站推广
  • 足球网站网站建设咸阳学校网站建设哪家好
  • 工程中标查询网站营销网站 深圳
  • Midb-Manager:轻量级前端数据管理利器,打造专属的.midb数据库
  • 上海网站开发售后服务qq登录网页版登录入口官网
  • 网站标题在哪里凡科网怎么制作小程序
  • linux声卡设置
  • 网站模板库软件前端网站大全
  • 让移动网站重庆百度网站排名
  • 整体设计 逻辑系统程序 之10 三种逻辑表述形式、形式化体系构建及关联规则(正则 / 三区逻辑)之3
  • 织梦模板建站wordpress 图片加链接地址
  • 华为OD机试C卷 - 寻找最大价值矿堆 - DFS - (Java C++ JavaScript Python)
  • 2025:现代硬件限制,系统设计考虑
  • 温州网站外包怎么用网站建设