杭电ACM1102——Constructing Roads

这题,简单的最小生成树的应用,只是输入的方式比较特殊。还会告诉你哪一些村庄是已经有路的。

输入的第一个数n,是村庄的数目,然后下面n * n 个数代表的是:第i行第j个就是村庄i和j之间的距离。

理解了这个,就很容易写出代码了。使用并查集避免形成环。

下面是AC的代码:

#include 
#include 
#include 
using namespace std;

class data                               //两个村庄直接的数据,也就是距离
{
public:
	int from, to, cost;
};

data Dis[12000];
int par[105], n, m, k;
int xy[105][105];                        //存输入的 m * m 个数

int cmp(const data& a, const data& b)    //从小到大排列
{
	return a.cost < b.cost;
}

int finds(int x)                          //并查集查找函数
{
	int r = x;
	while(r != par[r])
		r = par[r];
	int i = x, j;
	while(i != r)                        //路径压缩
	{ 
		j = par[i];
		par[i] = r;
		i = j;
	}
	return r;
}

void join(int x, int y)                  //并查集合并函数
{
	x = finds(x);
	y = finds(y);
	if(x != y)
		par[y] = x;
}

int Kru()                                //最小生成树算法
{
	int i; 
	sort(Dis, Dis + k, cmp);             //距离排序
	int ans = 0;
	for(i = 0; i < k; i++)
	{
		if(finds(Dis[i].from) != finds(Dis[i].to))   //判是否有环
		{
			ans += Dis[i].cost;
			join(Dis[i].from, Dis[i].to);         //合并
		}
	}
	return ans;
}

int main()
{
	int i, j;
	while(scanf("%d", &m) != EOF)            //输入m
	{
		k = 0;
		for(i = 1; i <= m; i++)               //输入m * m 个数
		{
			for(j = 1; j <= m; j++)
			{
				scanf("%d", &xy[i][j]);
			}
		}
		for(i = 1; i <= m; i++)               //将有用的距离取出
		{
			for(j = 1; j < i; j++)
			{
				Dis[k].from = i;
				Dis[k].to = j;
				Dis[k++].cost = xy[i][j];
			}
		}
		for(i = 0; i <= m; i++)               //初始化并查集
			par[i] = i;
		scanf("%d", &n);
		while(n--)                             //合并已有路的村庄
		{
			scanf("%d%d", &i, &j);
			join(i, j);
		}
		int ans = Kru();
		printf("%d\n", ans);
	}
	return 0;
}


你可能感兴趣的:(杭电,acm,杭电,kruskal)