P2941 [USACO09FEB]Surround the Islands S 题解

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.注意事项

这个代码中有几个地方需要注意,一个是在答案输出的时候时候要乘二,因为要往返一次,第二个是并查集要记得初始化!!!!(我调这个花了半个小时,我太菜了)。

完结撒花!!

上一篇:算法学习(二)—— 选择排序


下一篇:Islands and Bridges POJ - 2288