导言
//24.07.20 新生训练
——//感谢万能的学长
//注:本篇所用代码中,一部分为核心代码,非完整代码,读者使用时务必完善
最短路径
Floyd算法小代码(核心)
int g[N][N];
void solve()
{
memset(g, inf, sizeof g); // 默认是无穷大,inf=0x3f3f3f3f
cin >> n >> m;
int u, v, w;
for (int i = 1; i <= m; ++i)
{
g[i][i] = 0; // 自己到自己的距离是0
cin >> u >> v >> w;
g[u][v] = g[v][u] = w;
}
for (int k = 1; k <= n; ++k) // 枚举中间经过的节点
{
for (int i = 1; i <= n; ++i) // 枚举出发点
{
for (int j = 1; j <= n; ++j) // 枚举终点
{
if (g[i][k] + g[k][j] < g[i][j])
{
g[i][j] = g[i][k] + g[k][j];
}
}
}
}
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
cout << g[i][j] << ' ';
}
cout << '\n';
} // 每个点到每个点的最短路的矩阵
}
Dijkstra算法小代码
1. n * n 的Dijkstra(Acwing)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int N = 550;
int g[N][N];
int d[N];
bool st[N];
int n, m;
int dijkstra()
{
memset(d, 0x3f, sizeof d);
d[1] = 0;
for (int i = 0; i < n; i++)
{
int t = -1;
for (int j = 1; j <= n; j++) // 距离当前最近的那个节点
{
if (!st[j] && (t == -1 || d[j] < d[t]))
{
t = j;
}
}
st[t] = 1;
for (int j = 1; j <= n; j++)
{
d[j] == min(d[j], d[t] + g[t][j]);
}
}
if (d[n] == 0x3f3f3f3f)
return -1;
else
return d[n];
}
int main()
{
cin >> n >> m;
memset(g, 0x3f, sizeof g);
for (int i = 0; i < m; i++)
{
int u, v, w;
cin >> u >> v >> w;
g[u][v] = min(g[u][v], w);
}
int t = dijkstra();
cout << t << "\n";
}
2.(n + m)log(n) 的 dijkstra(Acwing)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 2e5 + 10;
typedef pair<int, int> PII;
vector<PII> g[N];
int d[N];
bool st[N];
int n, m;
// n*n
int dijkstra() // (n+m)log(n);
{
memset(d, 0x3f, sizeof d);
priority_queue<PII, vector<PII>, greater<PII>> q; //{当前点的距离,当前点是谁};
d[1] = 0;
q.push({0, 1});
while (q.size())
{
auto t = q.top();
q.pop();
int x = t.first, y = t.second;
if (st[y])
continue;
st[y] = 1;
// y: 由y进行更新所有邻边
// g[y].push_back({u,w});
for (int i = 0; i < g[y].size(); i++)
{
int u = g[y][i].first;
int w = g[y][i].second;
// 0x3f3f3f3f
if (d[u] > d[y] + w)
{
d[u] = d[y] + w;
q.push({d[u], u});
}
}
}
if (d[n] == 0x3f3f3f3f)
return -1;
else
return d[n];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int u, v, w;
cin >> u >> v >> w;
g[u].push_back({v,w}); // { , }
}
int t=dijkstra();
cout << t << "\n";
}
Bellman-Ford算法小代码(Acwing)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int N = 550;
const int M = 1e4 + 10;
struct node
{
int x, y, w;
} e[M];
int n, m, k;
int d[N], la[N];
void BF()
{
memset(d, 0x3f, sizeof d);
d[1] = 0;
int d[N], la[N];
for (int i = 0; i < k; i++)
{
memcpy(la, d, sizeof d); // 防止明明 k次到不了的点,却还被更新了
for (int j = 0; j < m; j++)
{
int a = e[j].x, b = e[j].y, c = e[j].w;
d[b] = min(d[b], la[a] + c);
}
}
if (d[n] > 0x3f3f3f3f / 2)
cout << "impossible\n";
else
cout << d[n] << "\n";
}
int main()
{
cin >> n >> m >> k;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
e[i] = {a, b, c};
}
BF();
return 0;
}
SPFA算法小代码(Acwing)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
vector<PII> g[N];
int n, m;
int d[N], cnt[N];
bool st[N];
int spfa()
{
memset(d, 0x3f, sizeof d);
queue<int> q;
d[1] = 0;
q.push(1);
st[1] = true;
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
// t
for (int i = 0; i < g[t].size(); i++)
{
int a = g[t][i].first, b = g[t][i].second;
if (d[a] > d[t] + b)
{
d[a] = d[t] + b;
cnt[a] = cnt[t] + 1;
if (cnt[a] >= n)
return false;
if (!st[a])
{
q.push(a);
st[a] = true;
}
}
}
}
return true;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
g[a].push_back({b, c});
}
int t = spfa();
if (t == 0x3f3f3f3f)
cout << "impossible\n";
else
cout << t << "\n";
}
SPFA判断负环(Acwing)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
vector<PII> g[N];
int n, m;
int d[N], cnt[N];
bool st[N];
int 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;
// t
for (int i = 0; i < g[t].size(); i++)
{
int a = g[t][i].first, b = g[t][i].second;
if (d[a] > d[t] + b)
{
d[a] = d[t] + b;
cnt[a] = cnt[t] + 1;
if (cnt[a] >= n)
return false;
if (!st[a])
{
q.push(a);
st[a] = true;
}
}
}
}
return true;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
g[a].push_back({b, c});
}
int t = spfa();
if (t == 0x3f3f3f3f)
cout << "impossible\n";
else
cout << t << "\n";
}
图的存储结构
邻接表(vector实现)存图,dfs与bfs(核心)
int n,m;
LL k;
vector<PII>g[N];
bool vis[N];
void dfs(int u){
vis[u]=1;
cout<<u<<' ';
for(auto &j:g[u]){
int w=j.first,v=j.second;
if(!vis[v]){
dfs(v);
}
}
}
void bfs(int st){
memset(vis,0,sizeof vis);
queue<int>q;
q.push(st);
vis[st]=1;
while(!q.empty()){
int u=q.front();
cout<<u<<' ';
q.pop();
for(auto &j:g[u]){
int w=j.first,v=j.second;
if(vis[v])continue;
vis[v]=1;
q.push(v);
}
}
}
void solve(){
cin>>n>>m;
int u,v,w;
for(int i=1;i<=m;++i){
cin>>u>>v>>w;
g[u].push_back({w,v});
g[v].push_back({w,u});
}
dfs(1);
cout<<'\n';
bfs(1);
}
链式前向星(核心)
int n,m;
LL k;
int head[N],to[N],w[N],ne[N],idx;
void add(int a,int b,int c){//每条边按输入顺序编号
to[idx]=b;//这条边到达的点
w[idx]=c;//这条边的权
ne[idx]=head[a];//最新的边的在链表中的下一个节点为链表当前的头节点
head[a]=idx;//最新的边作为链表的头节点
idx++;
}
bool vis[N];
void dfs(int u){
vis[u]=1;
cout<<u<<' ';
for(int i=head[u];~i;i=ne[i]){
int v=to[i];
if(!vis[v]){
dfs(v);
}
}
}
void bfs(int st){
memset(vis,0,sizeof vis);
queue<int>q;
q.push(st);
vis[st]=1;
while(!q.empty()){
int u=q.front();
cout<<u<<' ';
q.pop();
for(int i=head[u];~i;i=ne[i]){
int v=to[i];
if(vis[v])continue;
vis[v]=1;
q.push(v);
}
}
}
最小生成树
Prim算法小代码(Acwing)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
const int N = 550;
int g[N][N];
bool st[N];
int d[N];
int n, m;
void init()
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j)
g[i][j] = 0;
else
g[i][j] = 0x3f3f3f3f;
}
}
}
int prim()
{
int ans = 0;
memset(d, 0x3f, sizeof d);
for (int i = 0; i < n; i++)
{
int t = -1;
for (int j = 1; j <= n; j++)
{
if (!st[j] && (t == -1 || d[j] < d[t]))
t = j;
}
if (i > 0 && d[t] == 0x3f3f3f3f)
{
return -0x3f3f3f3f;
}
if (i > 0)
ans += d[t];
st[t] = true;
for (int j = 1; j <= n; j++)
{
d[j] = min(d[j], g[t][j]);
}
}
return ans;
}
int main()
{
cin >> n >> m;
init();
for (int i = 0; i < m; i++)
{
int u, v, w;
cin >> u >> v >> w;
g[u][v] = g[v][u] = min(g[u][v], w);
}
int t = prim();
if (t == -0x3f3f3f3f)
{
cout << "impossible\n";
}
else
cout << t << "\n";
return 0;
}
Kruskal算法小代码(Acwing)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int find(int x)
{
if (p[x] != x)
p[x] = find(p[x]);
return p[x];
}
struct node
{
int x, y, w;
bool operator<(const node &Z) const
{
return w < Z.w;
}
} e[N];
bool cmp(node &X, node &Y)
{
return X.w < Y.w;
}
int n, m;
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
p[i] = i;
}
for (int i = 0; i < m; i++)
{
cin >> e[i].x >> e[i].y >> e[i].w;
}
sort(e, e + m);
int cnt = 0, ans = 0;
for (int i = 0; i < m; i++)
{
int x = e[i].x, y = e[i].y, w = e[i].w;
int a = find(x), b = find(y);
if (a != b)
{
cnt++;
p[a] = b;
ans += w;
}
}
if (cnt != n - 1)
{
cout << "impossible\n";
}
else
cout << ans << "\n";
return 0;
}
拓扑排序
核心
int n,m;
LL k;
vector<int>g[N];
int in[N];
void toposort(){
queue<int>q;
for(int i=1;i<=n;++i){
if(!in[i]){
q.push(i);//入度为0的点进入队列
}
}
while(!q.empty()){
int u=q.front();
cout<<u<<' ';
q.pop();//弹出入队为0的点
for(auto &v:g[u]){
--in[v];//删除连接到节点v的边(入度减一)
if(!in[v]){
q.push(v);//入度为0,入队
}
}
}
}
void solve(){
cin>>n>>m;
int u,v,w;
for(int i=1;i<=m;++i){
cin>>u>>v;
g[u].push_back(v);
++in[v];//记录每个点的入度
}
toposort();
}
//笔者打了好几天,终于完工了 hwh
//这些大概就是C++图论的一些小代码了吧~
~~~仅当笔者个人备忘录使用。