ZOJ 3204 Connect them 继续MST

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3367

题目大意:

让你求最小生成树,并且按照字典序输出哪些点连接。无解输出-1

这里的字典序定义为:(不翻译啦~,详见我的比较函数)

A solution A is a line of p integers: a1, a2, ...ap.
Another solution B different from A is a line of q integers: b1, b2, ...bq.
A is lexicographically smaller than B if and only if:
(1) there exists a positive integer r (r <= p, r <= q) such that ai = bi for all 0 < i < r and ar < br 
OR
(2) p < q and ai = bi for all 0 < i <= p


思路:

进行kruskal之前排一次序,保证算法选择的边字典序小。

然后输出的时候也要排一次序。

什么时候无解?MST需要N-1条边才能连接所有顶点,所以你就看看边的条数呗。.。。

详见代码。

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=120;
const int INF=100000+10;
int fa[MAXN];
int n;

struct data
{
	int x,y;
	int dis;
}a[MAXN*MAXN],ans[MAXN];
bool operator< (const data& c,const data &d)
{
	if(c.dis<d.dis)
		return true;
	else if(c.dis==d.dis)
		return c.x<d.x || c.x==d.x && c.y < d.y ;
	return false;	
}

int find(int cur)
{
	return cur==fa[cur]? cur:fa[cur]=find(fa[cur]);
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		int len=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				scanf("%d",&a[len].dis);
				if(a[len].dis==0)
					continue;
				a[len].x=i;
				a[len].y=j;
				len++;
			}
		
		
		sort(a,a+len);				//保证kruskal的选边是按字典序来的

		for(int i=1;i<=n;i++)
			fa[i]=i;

		int lena=0;
		for(int i=0;i<len;i++)
		{
			int rootx=find(a[i].x);
			int rooty=find(a[i].y);
			if(rootx!=rooty)
			{
				fa[rootx]=rooty;
				ans[lena].x=a[i].x;
				ans[lena].dis=0;      //因为懒得在写比较函数,所以直接设为一样的吧
				ans[lena++].y=a[i].y;
			}
		}

		if(n-1!=lena)         //MST性质,肯定要n-1条边才能连接所有点
		{
			printf("-1\n");
			continue;
		}

		sort(ans,ans+lena); //保证输出边也是按字典序来的
		for(int i=0;i<lena;i++)
		{
			if(i!=0)
				printf(" ");
			printf("%d %d",ans[i].x,ans[i].y);
		}
		printf("\n");
	}

	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值