Highways C语言

The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has no public highways. So the traffic is difficult in Flatopia. The Flatopian government is aware of this problem. They're planning to build some highways so that it will be possible to drive between any pair of towns without leaving the highway system.

Flatopian towns are numbered from 1 to N. Each highway connects exactly two towns. All highways follow straight lines. All highways can be used in both directions. Highways can freely cross each other, but a driver can only switch between highways at a town that is located at the end of both highways.

The Flatopian government wants to minimize the length of the longest highway to be built. However, they want to guarantee that every town is highway-reachable from every other town.

Input
The first line of input is an integer T, which tells how many test cases followed.
The first line of each case is an integer N (3 <= N <= 500), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 65536]) between village i and village j. There is an empty line after each test case.
Output
For each test case, you should output a line contains an integer, which is the length of the longest road to be built such that all the villages are connected, and this value is minimum.
Sample Input

1

3
0 990 692
990 0 179
692 179 0

Sample Output

692

Hint
Huge input,scanf is recommended

本题的意思是找出生成树中两个城镇直接最短路径的最大值
这一题可以用prim算法也可以用KrusKal算法去求。不过由于题目给的数值较大,用KrusKal算法排序的时候需要注意,可能会导致时间超限

prim算法

#include<stdio.h>
int main()
{
	int T;
	scanf("%d", &T);//测试样例组数
	while (T--)
	{
		int n;
		scanf("%d", &n);//输入城镇个数
		int i, j, k, map[501][501];
		int dis[501];//记录未加入的城镇到生成树的最短距离
		int book[501] = { 0 };//用来标记城镇是否加入生成树
		int count, max, min;
		for (i = 1; i <= n; i++)
			for (j = 1; j <= n; j++)
				scanf("%d",&map[i][j]);//将城镇之间的距离存入二维数组
		for (i = 1; i <= n; i++)//先把第一个城镇到另外城镇直达的距离存入dis数组
			dis[i] = map[1][i];
		count = 1; max = 0;//先让最大值为零
		book[1] = 1;//先将第一个城镇加入生成树
		while (count < n)//当所有城镇都加入后结束循环
		{
		    min= 99999999;//先设一个自己认为的正无穷数,大于路线最大值即可
			for (i = 1; i <= n; i++)//从第一个城镇到最后一个一一排查
			{
				if (book[i] == 0 && dis[i] < min)//找出一个还未加入的城镇到生成树的最小距离
				{
					min = dis[i];
					j = i;
				}
			}
			count++;//加入生成树的城镇加一
			book[j] = 1;//标记当前城镇已加入生成树
			if (min > max)//找出生成树中两个城镇最短路径的最大值
			{
				max = min;
			}
			for (k = 1; k <= n; k++)//从第一个城镇到最后一个一一排查
			{
				if (book[k] == 0 && dis[k] > map[j][k])//找出未标记的城镇到更新过的生成树的最短距离并更新dis数组
					dis[k] = map[j][k];
			}
		}
		printf("%d\n",max);
	}
	}

KrusKal算法

#include<stdio.h>
struct note
{
	int x;
	int y;
	int z;  //x,y为城镇编号,z为二者的距离
};//用结构体储存各各城镇的距离
struct note a[250010], o;
int n, m;
int f[501] = { 0 };
void sort(int l, int r)//快速排序法
{
	int i, j;
	if (l > r)
		return;
	i = l;
	j = r;
	while (i != j)
	{
		while (a[j].z >= a[l].z && i < j)
			j--;
		while (a[i].z <= a[l].z && i < j)
			i++;
		if (i < j)
		{
			o = a[i];
			a[i] = a[j];
			a[j] = o;
		}
	}
	o = a[l];
	a[l] = a[i];
	a[i] = o;
	sort(l, i - 1);
	sort(i + 1, r);
	return;
}
int getf(int x)//使用并查集寻找祖先函数
{
	if (f[x] == x)
		return x;
	else
	{
		f[x] = getf(f[x]);
		return f[x];
	}
}
int merge(int x, int y)
{
	int t1, t2;
	t1 = getf(x);
	t2 = getf(y);
	if (t1 != t2)//判断两个点是否在同一集合中
	{
		f[t2] = t1;
		return 1;
	}
	return 0;
}
int main()
{
	int t, n;
	scanf("%d", &t);//输入测试样例个数
	while (t--)
	{
		int max = 0, count = 0;
		scanf("%d", &n);//输入城镇个数
		int i, j, k;
		k = 1;
		for(i=1; i<=n; i++)
			for (j = 1; j <= n; j++)
			{
				scanf("%d", &a[k].z);
				a[k].x = i ;
				a[k].y = j;
				k++;
			}
		k--;
		sort(1, k);//快速排序 这里如果使用冒泡排序会时间超限
		for (i = 1; i <= n; i++)//将城镇的编号存入数组中
			f[i] = i;
		for (i = 1; i <= k; i++)
		{
			if (merge(a[i].x, a[i].y))//判断两个城镇是否连通,若未连通则选用这条边
			{
				count++;
				if (max < a[i].z)//找出最大的那一条
				{
					max = a[i].z;
				}
			}
			if (count == n - 1)//当所有城镇都连通后
				break;
	   }
		printf("%d\n", max);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值