poj 1751 Highways 最小生成树 kruskal

题目链接

                https://cn.vjudge.net/problem/POJ-1751

题目大意

               输入n个城市的坐标, 并输入m对城市已经连接, 请输入还要哪些城市连接使得任意两个城市互通, 并边权之和达到最小

               "输入m对城市已经连接" 这地方我理解错了, 我以为这m对城市直接相连, 于是我原本写的是

for (int i = 1; i <= m; i++)
{
	int a, b;
	cin >> a >> b;
	fa[a] = fb;
}

                其实意思是这m对城市互通, 直接或间接.  所以应该是

	for (int i = 1; i <= m; i++)
	{
		int a, b;
		cin >> a >>b;
		int fa = find(a), fb = find(b);
		if (fa!=fb)
		fa[fa] = fb;
	}

还有一个地方我也写错了, 我以为m就是刚开始连接的边数, 其实m里面是可以有重复性的, 这也是我上面为什么加上  if(fa!=fb)

举个例子,有部分城市如图连接

m的输入可以是

3 2
2 5
1 2
2 4
1 5

第5行 1 5 是不是就没有意义了,  因为由前4行可以得出1 5 是相通的

所以kruskal判断循环结束的时候就出错了, 我原本写的是(第12行错误)

void kruskal()
{
	int num = 0;
	for (int i = 0; i < s; i++)
	{
		int fa = find(e[i].from), fb = find(e[i].to);
		if (fa != fb)
		{
			cout << e[i].from << ' ' << e[i].to << endl;
			per[fa] = fb;
			num++;
			if (num + m == n - 1) break;
		}
	}
}

m是原本已经通的边数, num是新添的边数, 根据树的性质: 边数=顶点数-1 ,  所以num+m==n-1 不就没错了?! ,  其实不然, m的意思并不是这个意思, 正如我上面举得例子, m=5, 其实只有4条边相通.

 

题目分析

              本题就是一个最小生成树的问题, 我采用的是kruskal法, 想方设法得到三大要素 e[i[.from, e[i].to, e[i].val,  套图模板即可

 

代码示例

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 10010
using namespace std;
const int maxn =5000000+5;

int per[N],n,m,s,res;
struct vet{ int x, y; }v[N];
struct node{ int from, to, val; }e[maxn];
bool cmp(node a, node b){ return a.val < b.val; }
int find(int x){ return per[x] == x ? x : per[x] = find(per[x]); }

void kruskal()
{
	int num = 0;
	for (int i = 0; i < s; i++)
	{
		int fa = find(e[i].from), fb = find(e[i].to);
		if (fa != fb)
		{
			cout << e[i].from << ' ' << e[i].to << endl;
			per[fa] = fb;
		}
	}
}
int main()
{
	cin >> n ;
	for (int i = 1; i <= n; i++)
	{
		per[i] = i;
		cin >> v[i].x >> v[i].y;
	}
	cin >> m;
	for (int i = 1; i <= m; i++)
	{
		int a, b;
		cin >> a >>b;
		int fa = find(a), fb = find(b);
		if (fa!=fb)
		per[fa] = fb;
	}
	s = 0;
	for (int i = 1; i <= n;i++)
	for (int j = i + 1; j <= n; j++)
	{
		if (find(i) == find(j)) continue;
		e[s].from = i;
		e[s].to = j;
		e[s++].val = (v[i].x - v[j].x)*(v[i].x - v[j].x) + (v[i].y - v[j].y)*(v[i].y - v[j].y);
	}
	sort(e, e + s, cmp);
	kruskal();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值