Sicily 1090 highway + Kruskal +并查集实现

Sicily 1090 highway

 

1.       并查集。

适用于集合论中,用来判断给出的两点A、B是否在同一个集合中,若不在一个集合中,则将他们合并。具体方法是维护2个一维数组:

Step1:初始化一维数组root[]使每个index存放自身,(即自己的root为自己,N个元素组成N个集合)

Index

1

2

3

4

5

6

7

8

root[index]

1

2

3

4

5

6

7

8

	for(int i=1;i<=n;i++)
		{
			root[i]=i;
		}

step2: 连接操作(克鲁斯卡尔中表现为 依次添加边)

 

Index

1

2

3

4

5

6

7

8

root[index]

1

1

1

4

1

6

7

6

 

Step3: 

 maintain an array to record the rank of eachset, initiate every single element. This array is intented to judge whetherSetA should be combined to SetB or SetB should be combined to SetA,mainlyaccording to the rank of the root.

	for(int i=1;i<=n;i++)
		{
			rankk[i]=0;
		}

Step4:


Index

1

2

3

4

5

6

7

8

root[index]

1

1

1

4

1

1

7

1

这时(6,8)集合被合并到(1,2,3,5)组合中,形成(1,2,3,5,6,8)(4)(7)组合。更新root[6] root[8], 这里有一点,为什么不是更新root[1] root[2] root[3] root[5]的值为6呢。这里依据的是step3中的rank数组值来判定。

 

Step5 依次类推,直到N个顶点的无向图形成N-1条边为止。

 

附:并查集core code:

int root(int a)
{
	if( a==vertex[a])
		return a;
	else
        return vertex[a]=root(vertex[a]);//update and maintain vertex[]; extraordinarily vital to update all nodes to a single root.
}

return vertex[a]=root(vertex[a]); //不采用return root(vertex[a]); 
将结构扁平化。集合中每个元素的root值统一为一个。

void merge(int a,int b)
{
	int roota=root(a);
	int rootb=root(b);
	if (rankk[roota]>rankk[rootb])
	{
		vertex[rootb]=roota;
	}
	else if (rankk[roota]<rankk[rootb])
	{
		vertex[roota]=rootb;
	}
	else
	{
		vertex[roota]=rootb;
		rankk[rootb]++;
	}
}

sicily 1090 highway的克鲁斯卡尔版本实现:

#include <iostream>
#include <algorithm>
using namespace std;

struct road{
	int a,b,distanc;
};
int vertex[501];
int rankk[501];
road ro[250000];
int arr[501][501];

bool cmp(const road &a,const road &b)  //add const & modifier
{
	return a.distanc<b.distanc;
}

int root(int a)
{
	if( a==vertex[a])
		return a;
	else
        return vertex[a]=root(vertex[a]);//update and maintain vertex[]; extraordinarily vital to update all nodes to a single root.
}

void merge(int a,int b)
{
	int roota=root(a);
	int rootb=root(b);
	if (rankk[roota]>rankk[rootb])
	{
		vertex[rootb]=roota;
	}
	else if (rankk[roota]<rankk[rootb])
	{
		vertex[roota]=rootb;
	}
	else
	{
		vertex[roota]=rootb;
		rankk[rootb]++;
	}
}

int main()
{
	int testcase;
	cin>>testcase;
	while (testcase--)
	{
		int n,temp;
		cin>>n;	
		int aa=0;
		for (int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				cin>>temp;
				arr[i][j]=temp;
				ro[aa].a=i;
				ro[aa].b=j;
				ro[aa].distanc=temp;
				aa++;
			}
		}
		sort(ro,ro+aa,cmp);
		int maxroad=0;
		for(int i=1;i<=n;i++)
		{
			vertex[i]=i;
			rankk[i]=0;
		}
		for(int i=0;i<aa;i++) 
		{
			int begi=ro[i].a;
			int end=ro[i].b;
			int weig=ro[i].distanc;
			if(root(begi)!=root(end))
			{
				merge(begi,end);
				maxroad=weig;
			}
		}
		cout<<maxroad<<endl;
		if (testcase!=0)
		{
			cout<<endl;
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值