P6464 传送门
感谢所有AC
传送门
思路
Floyd的本质是动态规划!
该图中存在两个点之间可以为 0 边权(可以是任意两点,这两点之间原来可以没有连边,所以不要误判成分层图!)
由于这两点的任意性,只能枚举两个点的位置情况,时间复杂度为 $O(n^2)$ ,在此基础上进行 Floyd算法就可以完成,时间复杂度为 $O(n^5)$, 不可接受。
考虑优化时间复杂度,由于只有两个点之间的权值改变,所有没有经过这两个点的路径依然不变,只需要更新经过这两个点的路径即可。因此把这两个点作为 Floyd 的中专点,分别做一次 Floyd ,得出的结果就是建立当前传送门的全源最短路。
考虑动态规划,定义 $f(i,j)$ 为从 $i$ 走到 $j$ 的最短路,如果该路径经过传送门 $(u,v)$ ,则该路径需要更新,可由 $f(i,u)+f(v,j)$ 或者 $f(i,v)+f(u,j)$ 转移。
代码
#include<iostream>
#include<cstring>
using namespace std;
int dis[150][150], ans = INT32_MAX, res;
int n, m;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
memset(dis, 1, sizeof(dis));
cin >> n >> m;
for (int i = 1; i <= n; i++)
dis[i][i] = 0;
for (int i = 1, u, v, w; i <= m; i++)
{
cin >> u >> v >> w;
dis[u][v] = dis[v][u] = w;
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
for (int l = 1; l < n; l++)
for (int r = l + 1; r <= n; r++)
{
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
res += min(dis[i][j], min(dis[i][l] + dis[r][j], dis[i][r] + dis[l][j]));
ans = min(ans, res);
res = 0;
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号