1.题目大意
这道题我认为配不上蓝题,我觉得这不科学,这道题的神奇之处在于它的题面描述十分的神奇。
中文翻译可能有一些问题,我们看看英文翻译,它要求我们在去到一个岛后立马回到原来的岛。这不就是一个菊花图吗??
2.代码实现
我们先用并查集来把环缩掉,然后直接枚举以每个节点为中心的菊花图,记得把答案乘\(2\)(我们要去一趟,回来一趟,共两趟),时间复杂度\(O(n^2)\)
有些大佬用Tarjan缩点,这样未免太麻烦,这个图是一个不联通的,每两个环之间没有其他的边连接!!!
#include <bits/stdc++.h>
using namespace std;
int n, fa[505];
int dis[505][505];
int ans = INT_MAX, tot;
int opt[505];
int getfa(int x) { //并查集的核心操作
if(x == fa[x]) return x;
return fa[x] = getfa(fa[x]); //路径压缩优化
}
int main() {
cin >> n;
memset(dis, 127, sizeof(dis)); //初始化两点之间的距离
for (int i = 1; i <= n ; i ++)
fa[i] = i; //并查集初始化
for (int i = 1; i <= n ; i ++) {
int x, y;
scanf("%d%d", &x, &y);
int fx = getfa(x), fy = getfa(y);
if (fx != fy) //如果在同一个并查集里面,说明这条线段是那个岛屿的一部分
fa[fx] = fy;
}
for (int i = 1; i <= n ; i ++) //统计总共有多少岛屿,并把它编号
if (fa[i] == i)
opt[++tot] = i;
for (int i = 1; i <= n ; i ++) {
int xxx = getfa(i);
for (int j = 1; j <= n ; j ++) {
int yyy = getfa(j);
int x;
scanf("%d", &x);
dis[xxx][yyy] = min(dis[xxx][yyy], x);//在输入的时候计算两个岛屿之间的最短路径
//注意,我们算的不是最短路,而是两个岛屿之间的直接路径的长度
}
}
for (int i = 1; i <= tot; i ++) { //以每个岛为菊花图的中心
int sum = 0;
for (int j = 1; j <= tot; j ++) {//枚举其他岛
if (i == j)
continue;
sum += dis[opt[i]][opt[j]];
}
ans = min(ans, sum);
}
cout << (ans << 1) << endl; //输出要乘二!!!
return 0;
}
3.注意事项
这个代码中有几个地方需要注意,一个是在答案输出的时候时候要乘二,因为要往返一次,第二个是并查集要记得初始化!!!!(我调这个花了半个小时,我太菜了)。
完结撒花!!