1.邻接矩阵
#include <iostream>
using namespace std;
int arr[105][105], n, m;
int main(int argc, char const *argv[])
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
arr[a][b] = c;
}
for (int i = 1; i <= n; i++)
{
cout << i << " : ";
for (int j = 1; j <= n; j++)
{
if (arr[i][j] != 0)
{
cout << "{" << i << "-->" << j << ", " << arr[i][j] << "} ";
}
}
cout << endl;
}
return 0;
}
2.弗洛伊德算法
用于求解最短路
特点:
①慢
②求解多源最短路(从任意点到任意点的最短路径)
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
arr[j][k] = min(arr[j][k], arr[j][i] + arr[i][k]);
}
}
}
③简单,好实现
代码实现:
#include <iostream>
#include <cstring>
using namespace std;
int arr[1005][1005], n, m, s;
int main(int argc, char const *argv[])
{
memset(arr, 0x3F, sizeof(arr));
cin >> n >> m >> s;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if (arr[a][b] > c) {
arr[a][b] = c;
arr[b][a] = c;
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
arr[j][k] = min(arr[j][k], arr[j][i] + arr[i][k]);
}
}
}
for (int i = 1; i <= n; i++)
{
arr[i][i] = 0;
if (arr[s][i] == 0x3F3F3F3F) {
cout << -1 << endl;
} else {
cout << arr[s][i] << endl;
}
}
return 0;
}
3.邻接表
特点:
①只存储有用信息,省空间
②可以以某个点为起点的所有边
与邻接矩阵互补!
邻接表实现:
#include <iostream>
using namespace std;
int n, m, edg[105][105];
int main(int argc, char const *argv[])
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b;
cin >> a >> b;
edg[a][++edg[a][0]] = b;
}
for (int i = 1; i <= n; i++)
{
cout << i << " : ";
for (int j = 1; j <= edg[i][0]; j++)
{
cout << edg[i][j] << " ";
}
cout << endl;
}
return 0;
}
节省内存的邻接表实现:
#include <iostream>
#include <vector>
using namespace std;
struct edge
{
int s, e, v;
};
int main(int argc, char const *argv[])
{
int n, m;
cin >> n >> m;
vector<vector<edge>> edg(n+5, vector<edge>());
for (int i = 0; i < m; i++)
{
//起点,终点,边权
int a, b, c;
cin >> a >> b >> c;
edg[a].push_back((edge){a, b, c});
}
for (int i = 1; i <= n; i++)
{
cout << i << " : ";
for (int j = 0; j < edg[i].size(); j++)
{
cout << "{" << i << "-->" << edg[i][j].e << ", " << edg[i][j].v << "}";
}
cout << endl;
}
return 0;
}
4.dijkstra算法
求解单源,没有负值!
每次找到该点到其它的点的最短路径。
代码实现:
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct node
{
int now, dis;
bool operator< (const node &b) const {
return this->dis > b.dis;
}
};
struct edge
{
int e, v;
};
int main(int argc, char const *argv[])
{
int n, m, s, ans[100005];
memset(ans, 0x3F, sizeof(ans));
// cin >> n >> m >> s;
scanf("%d%d%d", &n, &m, &s);
vector<vector<edge>> edg(n+5, vector<edge>());
for (int i = 0; i < m; i++)
{
int a, b, c;
// cin >> a >> b >> c;
scanf("%d%d%d", &a, &b, &c);
edg[a].push_back((edge){b, c});
edg[b].push_back((edge){a, c});
}
priority_queue<node> que;
que.push((node){s, 0});
ans[s] = 0;
while (!que.empty())
{
node temp = que.top();
que.pop();
if (ans[temp.now] < temp.dis) {
continue;
}
for (int i = 0; i < edg[temp.now].size(); i++)
{
int e = edg[temp.now][i].e, v = edg[temp.now][i].v;
if (ans[e] > temp.dis + v) {
ans[e] = temp.dis + v;
que.push((node){e, ans[e]});
}
}
}
for (int i = 1; i <= n; i++)
{
if (ans[i] == 0x3F3F3F3F) {
// cout << -1 << endl;
printf("-1\n");
} else {
// cout << ans[i] << endl;
printf("%d\n", ans[i]);
}
}
return 0;
}
5.链式前向星
用指针域模拟一个链表。
代码实现:
#include <iostream>
#include <cstring>
using namespace std;
struct edge
{
int e, v, next;
};
edge edg[1005];
int n, m, head[1005];
int main(int argc, char const *argv[])
{
memset(head, -1, sizeof(head));
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
edg[i].e = b; //终点
edg[i].v = c; //权值
edg[i].next = head[a]; //同起点的上一条边
head[a] = i; //a的最后一条边
}
for (int i = 1; i <= n; i++)
{
cout << i << " : ";
for (int j = head[i]; j != -1; j = edg[j].next)
{
cout << "{" << i << "-->" << edg[j].e << ", " << edg[j].v << "} ";
}
cout << endl;
}
return 0;
}
基于dijkstra链式前向星代码实现:
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
struct edge
{
int e, v, next;
};
struct node
{
int now, dis;
bool operator< (const node &b) const {
return this->dis > b.dis;
}
};
edge edg[200005];
int n, m, s, ans[100005], head[100005], cnt;
void add_edge(int a, int b, int c) {
edg[cnt].e = b;
edg[cnt].v = c;
edg[cnt].next = head[a];
head[a] = cnt;
cnt++;
}
int main(int argc, char const *argv[])
{
memset(head, -1, sizeof(head));
memset(ans, 0x3F, sizeof(ans));
cin >> n >> m >> s;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add_edge(a, b, c);
add_edge(b, a, c);
}
priority_queue<node> que;
que.push((node){s, 0});
ans[s] = 0;
while (!que.empty())
{
node temp = que.top();
que.pop();
if (temp.dis > ans[temp.now]) {
continue;
}
for (int i = head[temp.now]; i != -1; i = edg[i].next)
{
int e = edg[i].e, v = edg[i].v;
if (ans[e] > ans[temp.now] + v) {
ans[e] = ans[temp.now] + v;
que.push((node){e, ans[e]});
}
}
}
for (int i = 1; i <= n; i++)
{
if (ans[i] == 0x3F3F3F3F) cout << -1 << endl;
else cout << ans[i] << endl;
}
return 0;
}
6.Bellman-ford
特点:单源最短路径,处理速度比较慢,但可以处理负权边。
代码实现:
#include <iostream>
#include <cstring>
using namespace std;
struct edge
{
int s, e, v;
};
edge edg[200005];
int n, m, s, ans[100005], cnt;
void add_edge(int a, int b, int c) {
edg[cnt].s = a;
edg[cnt].e = b;
edg[cnt].v = c;
cnt++;
}
int main(int argc, char const *argv[])
{
memset(ans, 0x3F, sizeof(ans));
cin >> n >> m >> s;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add_edge(a, b, c);
add_edge(b, a, c);
}
ans[s] = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < cnt; j++)
{
if (ans[edg[j].e] > ans[edg[j].s] + edg[j].v) {
ans[edg[j].e] = ans[edg[j].s] + edg[j].v;
}
}
}
for (int i = 1; i <= n; i++)
{
if (ans[i] == 0x3F3F3F3F) cout << -1 << endl;
else cout << ans[i] << endl;
}
return 0;
}
时间复杂度是O(n * m)
优化:
#include <iostream>
#include <cstring>
using namespace std;
struct edge
{
int s, e, v;
};
edge edg[200005];
int n, m, s, ans[100005], cnt;
void add_edge(int a, int b, int c) {
edg[cnt].s = a;
edg[cnt].e = b;
edg[cnt].v = c;
cnt++;
}
int main(int argc, char const *argv[])
{
memset(ans, 0x3F, sizeof(ans));
cin >> n >> m >> s;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add_edge(a, b, c);
add_edge(b, a, c);
}
ans[s] = 0;
for (int i = 0; i < n; i++)
{
int f = 0;
for (int j = 0; j < cnt; j++)
{
if (ans[edg[j].e] > ans[edg[j].s] + edg[j].v) {
ans[edg[j].e] = ans[edg[j].s] + edg[j].v;
f = 1;
}
}
if (f == 0) break;
}
for (int i = 1; i <= n; i++)
{
if (ans[i] == 0x3F3F3F3F) cout << -1 << endl;
else cout << ans[i] << endl;
}
return 0;
}
只有上一轮更新过的点,才能影响下一轮答案
->基于队列的bellman-ford算法的优化:
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
struct edge
{
int e, v, next;
};
edge edg[200005];
int n, m, s, ans[100005], head[100005], cnt, mark[100005];
void add_edge(int a, int b, int c) {
edg[cnt].e = b;
edg[cnt].v = c;
edg[cnt].next = head[a];
head[a] = cnt++;
}
int main(int argc, char const *argv[])
{
memset(ans, 0x3F, sizeof(ans));
memset(head, -1, sizeof(head));
cin >> n >> m >> s;
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
add_edge(a, b, c);
add_edge(b, a, c);
}
queue<int> que;
ans[s] = 0;
que.push(s);
mark[s] = 1;
while (!que.empty())
{
int temp = que.front();
que.pop();
mark[temp] = 0;
for (int i = head[temp]; i != -1; i = edg[i].next)
{
int e = edg[i].e, v = edg[i].v;
if (ans[e] > ans[temp] + v) {
ans[e] = ans[temp] + v;
if (mark[e] == 0) {
que.push(e);
mark[e] = 1;
}
}
}
}
for (int i = 1; i <= n; i++)
{
if (ans[i] == 0x3F3F3F3F) cout << -1 << endl;
else cout << ans[i] << endl;
}
return 0;
}
7.code
#include <iostream>
#include <cstring>
using namespace std;
int n, num[105], arr[105][105];
int main(int argc, char const *argv[])
{
memset(arr, 0x3F, sizeof(arr));
// cin >> n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
int a, b;
scanf("%d%d", &a, &b);
if (a) {
arr[i][a] = 1;
arr[a][i] = 1;
}
if (b) {
arr[i][b] = 1;
arr[b][i] = 1;
}
arr[i][i] = 0;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
arr[j][k] = min(arr[j][k], arr[j][i] + arr[i][k]);
}
}
}
int ans = 0x3F3F3F3F;
for (int i = 1; i <= n; i++)
{
int t = 0;
for (int j = 1; j <= n; j++)
{
t += arr[j][i] * num[j];
}
ans = min(ans, t);
}
printf("%d\n", ans);
return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
int n, m, q, now, num[205], arr[205][205];
int main(int argc, char const *argv[])
{
memset(arr, 0x3F, sizeof(arr));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
arr[i][i] = 0;
}
for (int i = 0; i < m; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
a++, b++;
arr[a][b] = arr[b][a] = c;
}
scanf("%d", &q);
for (int i = 0; i < q; i++)
{
int x, y, t;
scanf("%d%d%d", &x, &y, &t);
x++, y++;
while (num[now] <= t && now <= n)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
arr[j][k] = min(arr[j][k], arr[j][now] + arr[now][k]);
}
}
now++;
}
if (num[x] > t || num[y] > t || arr[x][y] == 0x3F3F3F3F) printf("-1\n");
else printf("%d\n", arr[x][y]);
}
return 0;
}