1. 程式人生 > 實用技巧 >[USACO2.4]牛的旅行 Cow Tours

[USACO2.4]牛的旅行 Cow Tours

題目描述:這裡

思路:

首先,先對整個圖進行判連通塊,用並查集即可(這一步很重要,因為這可以降低時間複雜度)。

其次,對整個圖用求區域內的最短路。

然後,進行暴力,對於不在一個連通塊內的兩個點,嘗試連線它們,求直徑的最小值。

注意點:將兩個牧場連通後,直徑如果要經過新路,可能還比原來牧場的直徑小,所以要進行特判。

程式碼部分:

#include<bits/stdc++.h>
using namespace std;

const long double INF = 0x3f3f3f3f3f3f3f3f;

struct dot
{
	int x, y;
}temp[155];

long double len(int x, int y)
{
	return (long double)sqrt((long double)(temp[x].x - temp[y].x) * (long double)(temp[x].x - temp[y].x) + (long double)(temp[x].y - temp[y].y) * (long double)(temp[x].y - temp[y].y));
}

int n;
long double d[155][155];
long double dis[155];

void floyed()
{
    for(int k = 1;k <= n;k++)
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= n;j++)
                if(d[i][k] != INF && d[k][j] != INF && d[i][j] > d[i][k] + d[k][j])
                    d[i][j] = d[i][k] + d[k][j];
}

int fa[155];

void init()
{
	for(int i = 1;i <= n;i++)
		fa[i] = i;
}

int find(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
}

void merge(int x, int y)
{
	fa[find(x)] = find(y);
}

int main() 
{
	cin >> n;
	init();
	for(int i = 1;i <= n;i++)
		cin >> temp[i].x >> temp[i].y;
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= n;j++)
		{
			char c;
			cin >> c;
			if(c == '1') 
			{
				d[i][j] = len(i, j);
				merge(i, j);
			}
			else d[i][j] = INF;
		}
	floyed();
	long double ans = 0x3f3f3f3f3f3f3f3f, sum = 0, maxa = INT_MIN, maxb = INT_MIN;
	int mina, minb;
	for(int i = 1;i <= n;i++)
		for(int j = i + 1;j <= n;j++)
			if(find(i) != find(j))
			{
				sum += len(i, j);
				mina = i;
				minb = j; 
				for(int k = 1;k <= n;k++)
					if(find(mina) == find(k) && k != mina)
					{
						if(d[mina][k] != INF) maxa = max(maxa, d[mina][k]);
						if(d[k][mina] != INF) maxa = max(maxa, d[k][mina]);
					}
				if(maxa >= 0) sum += maxa;
				for(int k = 1;k <= n;k++)
					if(find(minb) == find(k) && k != minb)
					{
						if(d[minb][k] != INF) maxb = max(maxb, d[minb][k]);
						if(d[k][minb] != INF) maxb = max(maxb, d[k][minb]);
					}
				if(maxb >= 0) sum += maxb;
				ans = min(ans, sum);
				sum = 0;
				maxa = INT_MIN, maxb = INT_MIN;
			}
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= n;j++)
			if(d[i][j] != INF) 
				dis[i] = max(dis[i], d[i][j]);
	for(int i = 1;i <= n;i++)
		ans = max(ans, dis[i]);
	cout << fixed << setprecision(6) << ans << endl;
	return 0;
}