多源最短路


B3647 【模板】Floyd - 洛谷

cpp
#include<iostream>
#include<cstring>
using namespace std;
const int N = 110;
int f[N][N];
int n, m;
int main()
{
memset(f, 0x3f, sizeof(f));//对于重边的处理取较小值,所以要把全部都初始化成无穷大,以避免对数据的影响
cin >> n >> m;
for (int i = 1; i <= n; i++)//自己到自己都是0
f[i][i] = 0;
for (int i = 1; i <= m; i++)
{
int u, v, w; cin >> u >> v >> w;
f[u][v] = f[v][u] = min(w, f[u][v]);//对重边+无向图的处理
}
for (int k = 1; k <= n; k++)//逐步加入k个点
{
for (int i = 1; i <= n; i++)//起点
{
for (int j = 1; j <= n; j++)//终点
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);//k是中转点
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << f[i][j] << " ";
}
cout << endl;
}
return 0;
}
状态表⽰: f[k][i][j] 表⽰:仅仅经过[1, k] 这些点,结点i ⾛到结点j 的最短路径 的⻓度。
状态转移⽅程:
• 第⼀种情况,不选新来的点: f[k][i][j] = f[k - 1][i][j] ;
• 第⼆种情况,选择新来的点: f[k][i][j] = f[k - 1][i][k] + f[k - 1][k][j],
i->k的路径+k到j的路径之和,把k作为中转点。找以k为中转点,i到j是否存在更小的路径,存在的话,那就更新,不在的话,那就维持原判。
空间优化:只会⽤到上⼀层的状态,因此可以优化到第⼀维。
初始化:
• f[i][i] = 0 ;
• f[i][j] 为初始状态下i 到j 的距离,如果没有边则为⽆穷。
- 填表顺序:
• ⼀定要先枚举k ,再枚举i 和j 。因为我们填表的时候,需要依赖的是k - 1 层的状态,因 此k 必须先枚举。
P2910 [USACO08OPEN] Clear And Present Danger S - 洛谷

cpp
#include<iostream>
using namespace std;
const int N = 110;
const int M = 1e4 + 10;
int n, m;
int a[M];
int f[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)cin >> a[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> f[i][j];
//floyd算法
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
//加上
long long ret = 0;
for (int i = 1; i < m; i++)
{
ret += f[a[i]][a[i+1]];
}
cout << ret << endl;
}
P1119 灾后重建 - 洛谷

本题的t是保证不下降的->可以使用floyd算法不断加点。
cpp
#include<iostream>
#include<cstring>
using namespace std;
const int N = 210;
const int M = 2e4 + 10;
const int INF = 0x3f3f3f3f;
int f[N][N];
int t[N];
int n, m;
void floyd(int k)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
int main()
{
cin >> n >> m;
memset(f, INF, sizeof(f));
for (int i = 0; i < n; i++)f[i][i] = 0;
for (int i = 0; i < n; i++)cin >> t[i];
for (int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
f[a][b] = f[b][a] = min(f[a][b], c);//无向边的处理,!!!!!!
}
int q; cin >> q;
int pos = 0;
while (q--)
{
int a, b, c; cin >> a >> b >> c;
while (pos<n&&t[pos] <= c)//pos记录当前符合时间条件可以加进去的地点,不可以超过n
floyd(pos++);
}
if (t[a] > c || t[b] > c || f[a][b] == INF)cout << -1 << endl;
else cout << f[a][b] << endl;
}
return 0;
}
P6175 无向图的最小环问题 - 洛谷

从上面找最小环
下面用floyd算法找最小距离
cpp
#include<iostream>
using namespace std;
const int N = 110;
const int M = 5e3 + 10;
const int INF = 1e8;
int n, m;
int e[N][N];
int f[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
e[i][j] = e[j][i] = f[i][j] = f[j][i] = INF;
}
}
for (int i = 1; i <= m; i++)
{
int a, b, c; cin >> a >> b >> c;
e[a][b] = e[b][a] = f[a][b] = f[b][a] = min(f[a][b], c);
}
int ret = INF;
for (int k = 1; k <= n; k++)
{
//最小环
for (int i = 1; i < k; i++)
{
for (int j = i + 1; j < k; j++)
{
ret = min(ret, f[i][j] + e[i][k] + e[k][j]);
}
}
//最小距离
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
if (ret == INF)cout << "No solution." << endl;
else cout << ret << endl;
return 0;
}