ZOJ-3204

Kruskal最小生成树,边排序的时候同时要将点排序,因为结果要求按字典序输出。注意全连通的条件是边数刚好等于顶点数减一,刚开始想错了,WA了几次,TAT,图论基础不行啊

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct Computer
{
	int index;
	struct Computer *parent;
	int rank;
};

struct Connect
{
	struct Computer *u;
	struct Computer *v;
	int cost;
};

static struct Computer *make_set(int index)
{
	struct Computer *v = malloc(sizeof(struct Computer));
	v->index = index;
	v->parent = v;
	v->rank = 0;
	return v;
}

static struct Computer *find_set(struct Computer *v)
{
	if (v->parent != v)
		v->parent = find_set(v->parent);
	return v->parent;
}

static void link(struct Computer *u, struct Computer *v)
{
	if (u->rank > v->rank)
		v->parent = u;
	else
	{
		u->parent = v;
		if (u->rank == v->rank)
			v->rank++;
	}
}

static void union_set(struct Computer *u, struct Computer *v)
{
	link(find_set(u), find_set(v));
}

static int cmp(const void *p1, const void *p2)
{
	struct Connect *c1 = (struct Connect*) p1;
	struct Connect *c2 = (struct Connect*) p2;
	if (c1->cost != c2->cost)
		return c1->cost - c2->cost;
	else if (c1->u->index != c2->u->index)
		return c1->u->index - c2->u->index;
	else
		return c1->v->index - c2->v->index;
}

int main()
{
	int t, i, j, n, map[100][100];
	scanf("%d", &t);
	struct Computer **array = malloc(100 * sizeof(struct Computer*));
	struct Connect *net = malloc(5000 * sizeof(struct Connect));
	for (i = 0; i < 100; i++)
		array[i] = make_set(i);
	while (t--)
	{
		scanf("%d", &n);
		for (i = 0; i < n; i++)
		{
			array[i]->parent = array[i];
			array[i]->rank = 0;
		}
		for (i = 0; i < n; i++)
			for (j = 0; j < n; j++)
				scanf("%d", &map[i][j]);

		int total = 0, res = 0;
		for (i = 0; i < n; i++)
			for (j = i + 1; j < n; j++)
			{
				if (!map[i][j])
					continue;
				net[total].u = array[i];
				net[total].v = array[j];
				net[total++].cost = map[i][j];
			}
		qsort(net, total, sizeof(struct Connect), cmp);

		for (i = 0; i < total; i++)
		{
			struct Computer *c1 = find_set(net[i].u);
			struct Computer *c2 = find_set(net[i].v);
			if (c1 != c2)
			{
				union_set(c1, c2);
				net[i].cost = 0;
				res++;
			}
		}
		qsort(net, total, sizeof(struct Connect), cmp);

		if (res == n - 1)
		{
			for (i = 0; i < res; i++)
				printf(i ? " %d %d" : "%d %d", net[i].u->index + 1,
						net[i].v->index + 1);
			putchar('\n');
		}
		else
			puts("-1");

	}
	for (i = 0; i < n; i++)
		free(array[i]);
	free(net);
	free(array);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值