#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e4 + 10;
const int INF = 2147483647;
vector<PII> edge[N];//i后面接的点j,和到j的距离
bool st[N];//是否已经确定是最优解
int dist[N];//起点到个点的最小值
int n, m, s;
void dijksta()
{
for (int i = 1; i < n; i++)
{
int a = 0;
for (int i = 1; i <= n; i++)//找目前dist中的最小值
{
if (!st[i] && dist[i] < dist[a])a = i;//没有被确定最优,且最小
}
st[a] = true;
for (auto& ch : edge[a])//更新:松弛操作
{
int v = ch.first, w = ch.second;
if (dist[v] > dist[a] + w)
{
dist[v] = dist[a] + w;
}
}
}
for (int i = 1; i <= n; i++)cout << dist[i] << " ";
}
int main()
{
cin >> n >> m >> s;
for (int i = 1; i <= m; i++)
{
int x, y, z;
cin >> x >> y >> z;
edge[x].push_back({ y,z });
}
for (int i = 0; i <= n; i++)dist[i] = INF;//如果要初始化的数字太大,那就用不了memset
dist[s] = 0;//初始化起点
dijksta();
return 0;
}
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int n, m,s;
vector<PII> edge[N];
bool st[N];
int dis[N];
priority_queue<PII,vector<PII>,greater<PII>> q;
void dijkstra()
{
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
q.push({ 0,s });//先存距离,后存结点,因为,greater会根据第一个数据first进行小跟堆排序
while (q.size())
{
auto t = q.top(); q.pop();
int a = t.second;
if (st[a])continue;
st[a] = true;
for (auto& x : edge[a])
{
int b = x.first, c = x.second;
if (dis[a] + c < dis[b])
{
dis[b] = dis[a] + c;
q.push({ dis[b], b });
}
}
}
for (int i = 1; i <= n; i++)cout << dis[i] << " ";
}
int main()
{
cin >> n >> m>>s;
for (int i = 1; i <= m; i++)
{
int a, b, c; cin >> a >> b >> c;
edge[a].push_back({ b,c });
}
dijkstra();
return 0;
}
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e4 + 10;
const int INF = 2147483647;
typedef pair<int, int> PII;
vector<PII> edge[N];
int dis[N];
int n, m , s;
void BF()
{
for (int i = 1; i <= n; i++)dis[i] = INF;
dis[s] = 0;
for (int i = 1; i < n; i++)//n-1条边,那就n-1次就好
{
bool judge = false;//没有了松弛操作,就退出
for (int j = 1; j <= n; j++)//遍历全部
{
if (dis[j] == INF)continue;//if (dis[j] + b < dis[a]),这一步+,会让超出int范围变成负数,
for (auto& x : edge[j])
{
int a = x.first, b = x.second;
if (dis[j] + b < dis[a])
{
dis[a] = dis[j] + b;
judge = true;//有松弛操作
}
}
}
if (judge == false)break;
}
for (int i = 1; i <= n; i++)
{
if (dis[i] != INF)cout << dis[i] << " ";
else cout << INF << " ";
}
}
int main()
{
cin >> n >> m >> s;
for (int i = 1; i <= m; i++)
{
int x, y, z; cin >> x >> y >> z;
edge[x].push_back({ y,z });
}
BF();
}
spfa算法:用队列对BF算法进行优化
cpp复制代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N = 1e4 + 10;
const int INF = 2147483647;
typedef pair<int, int> PII;
vector<PII> edge[N];
int dis[N];
int n, m , s;
queue<PII> q;
bool st[N];
void BF()
{
for (int i = 1; i <= n; i++)dis[i] = INF;
dis[s] = 0;
q.push({ s,0 });
st[s] = true;
while (q.size())
{
auto t = q.front(); q.pop();
int a = t.first, b = t.second;
for (auto& x : edge[a])
{
int y = x.first, z = x.second;
if (dis[a] + z < dis[y])
{
dis[y] = dis[a] + z;
if(!st[y])
q.push({ y, dis[y] });
st[y] = true;
}
}
}
for (int i = 1; i <= n; i++)
{
if (dis[i] != INF)cout << dis[i] << " ";
else cout << INF << " ";
}
}
int main()
{
cin >> n >> m >> s;
for (int i = 1; i <= m; i++)
{
int x, y, z; cin >> x >> y >> z;
edge[x].push_back({ y,z });
}
BF();
}
#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e3 + 10;
const int M = 3e3 + 10;
int T, n, m;
int pos;//记录边的个数
struct node
{
int u, v, w;
}edge[M*2];
int dis[N];
bool bf()
{
memset(dis, 0x3f3f3f3f, sizeof(dis));
dis[1] = 0;//出发点
bool flag;
for (int i = 1; i <= n; i++)
{
flag = false;
for (int j = 1; j <= pos; j++)
{
int a = edge[j].u, b = edge[j].v, c = edge[j].w;
if (dis[a] == 0x3f3f3f3f)continue;
if (dis[a] + c < dis[b])
{
dis[b] = dis[a] + c;
flag = true;
}
}
if (flag == false)return flag;//如果在n-1次到来前退出循环,说明,没有负环,返回false
}
return flag;//如果n-1次循环都没有返回false,那么就一定存在负环
}
int main()
{
cin >> T;
while (T--)
{
cin >> n >> m;
pos = 0;
for (int i = 1; i <= m; i++)
{
int x, y, z; cin >> x >> y >> z;
++pos;
edge[pos].u = x, edge[pos].v = y, edge[pos].w = z;
if (z >= 0)
{
++pos;
edge[pos].u = y, edge[pos].v = x, edge[pos].w = z;
}
}
if (bf())cout << "YES" << endl;
else cout << "NO" << endl;
}
}
spfa算法实现
cpp复制代码
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<int, int> PII;
const int N = 2e3 + 10;
const int M = 3e3 + 10;
int t, n, m;
vector<PII> edge[N];
int dis[N];
bool st[N];
int cnt[N];
bool spfa()
{
//清除
memset(dis, 0x3f, sizeof(dis));//一开始无穷大
memset(cnt, 0, sizeof(cnt));//0
memset(st, false, sizeof(st));//false
//初始化
queue<int> q;
q.push(1);//推入1
//初始化
dis[1] = 0;
st[1] = true;
cnt[1] = 0;
while (q.size())
{
int x = q.front(); q.pop();
st[x] = false;
for (auto& ch : edge[x])
{
int a = ch.first, b = ch.second;
if (dis[x] + b < dis[a])
{
dis[a] = dis[x] + b;
if (!st[a])
{
q.push(a);
st[a] = true;
}
cnt[a] = cnt[x] + 1;
if (cnt[a] >= n)return true;
}
}
}
return false;
}
int main()
{
cin >> t;
while (t--)
{
//清除
for (int i = 1; i <= n; i++)edge[i].clear();
cin >> n >> m;
//输入
for (int i = 1; i <= m; i++)
{
int a, b, c; cin >> a >> b >> c;
edge[a].push_back({ b,c });
if (c >= 0)
{
edge[b].push_back({ a,c });
}
}
//大框架
if (spfa())cout << "YES" << endl;
else cout << "NO" << endl;
}
}
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e3 + 10;
int n, m;
int edge[N][N];
int dis[N];
bool st[N];
void dijkstra()
{
memset(dis, 0x3f, sizeof(dis));
memset(st, false, sizeof(st));
dis[1] = 0;
for (int i = 1; i <= n; i++)//n次操作
{
int t = 0;
for (int j = 1; j <= n; j++)
{
if (!st[j] && dis[j] < dis[t])t = j;//未标记加《dis[t]
}
st[t] = true;
for (int j = 1; j <= n; j++)
{
if (!st[j] && edge[t][j]+dis[t] < dis[j])
{
dis[j] = edge[t][j] + dis[t];
}
}
}
}
int main()
{
cin >> n >> m;
memset(edge, 0x3f, sizeof(edge));
for (int i = 1; i <= m; i++)
{
int x, y, z;
cin >> x >> y >> z;
edge[x][y] = min(edge[x][y], z);
}
dijkstra();
int ret = 0;
for (int i = 1; i <= n; i++)ret += dis[i];
//推反图
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i >= j)continue;
swap(edge[i][j], edge[j][i]);
}
}
dijkstra();
for (int i = 1; i <= n; i++)ret += dis[i];
cout << ret << endl;
}
#include<iostream>
#include<cmath>
using namespace std;
const int N = 110;
const int M = 1010;
int x[N], y[N];//店铺的坐标
struct node
{
int s;//头
int e;//尾
double v;//长
}ed[M];//记录边1
int n;//how many shops
int m;//通路
int star, en;//起点-终点
double dis[N];//起点到各点的距离
double cal(int i, int j)//计算
{
double a = x[i] - x[j];
double b = y[i] - y[j];
return sqrt(a * a + b * b);
}
void BF()
{
for (int i = 1; i <= n; i++) dis[i] = 1e10;//过大
dis[star] = 0;
for (int i = 1; i < n; i++)//n-1次操作
{
for (int j = 1; j <= m; j++)//每个边都遍历一遍
{
int s = ed[j].s;
int e = ed[j].e;
double v = ed[j].v;
if (dis[s] + v < dis[e])
{
dis[e] = dis[s] + v;//更新
}
if (dis[e] + v < dis[s])
{
dis[s] = dis[e] + v;//更新,重边,没说有向边那就可能存在重边
}
}
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> x[i] >> y[i];
}
cin >> m;
for (int i = 1; i <= m; i++)
{
int a, b; cin >> a >> b;
ed[i].s = a, ed[i].e = b;
ed[i].v = cal(a, b);
}
cin >> star >> en;
BF();
printf("%.2lf", dis[en]);
return 0;
}
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010;
const int M = 1e4+10;
int n, m;
struct node
{
int x, y, z;
}e[M];
int dis[N];
bool BF(int s)
{
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
bool flag = true;
for (int i = 1; i <= n; i++)
{
flag = false;
for (int j = 1; j <= m; j++)
{
int a = e[j].x, b = e[j].y, c = e[j].z;//老是把这个地方写成i记得改!!!!
if (dis[a] + c < dis[b])
{
dis[b] = dis[a] + c;//更新
flag = true;//更新
}
}
if (flag == false)return flag;
}
return true;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> e[i].x >> e[i].y >> e[i].z;
e[i].z = -e[i].z;
}
//起点是1
//双向的求最小
if (BF(1))
{
cout << "Forever love" << endl;//有负环
return 0;
}
int ret1 = dis[n];//记录
//起点是n
if (BF(n))
{
cout << "Forever love" << endl;//有负环
return 0;
}
int ret2 = dis[1];
cout << min(ret1, ret2) << endl;
}
bf或者spfa
双向求最小,两边都要进行遍历
int a = e[j].x, b = e[j].y, c = e[j].z;//老是把这个地方写成i记得改!!!!