2019年第十届蓝桥杯研究生组 试题 H: 修改数组(并查集)

题目链接:点击这里
2019年第十届蓝桥杯研究生组 试题 H: 修改数组(并查集)_第1张图片
2019年第十届蓝桥杯研究生组 试题 H: 修改数组(并查集)_第2张图片

使用vis数组标记判重,可以通过80%。当数组元素全部相同时,时间复杂度为 O ( n ( n − 1 ) 2 ) O(\frac{n(n-1)}{2}) O(2n(n1)),会超时:

#include
#include
#include
#include

using namespace std;

int a[100010];
bool vis[1000010];

int main()
{
	int n;
	scanf("%d", &n);
	
	for(int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	
	vis[a[1]] = true;
	for(int i = 2; i <= n; ++i)
	{
		while(vis[a[i]])
		{
			a[i]++;
		}
		vis[a[i]] = true;
	}
	
	for(int i = 1; i <= n; ++i)
		printf("%d ", a[i]);
	
	return 0;
}

搜题解思路:

这题可以巧妙地利用并查集。 我们初始化 i i i 的父亲为 i i i,然后依次遍历输入的数组,使 a [ i ] = f i n d ( a [ i ] ) a[i] = find(a[i]) a[i]=find(a[i]),再令 f [ a [ i ] ] = f i n d ( a [ i ] + 1 ) f[a[i]] = find(a[i]+1) f[a[i]]=find(a[i]+1) 即可。

假如数组为 1 , 2 , 1 1, 2, 1 1,2,1

  1. 第一次输入 1 1 1 a [ 1 ] = f i n d ( a [ 1 ] ) = f i n d ( 1 ) = 1 a[1] = find(a[1]) = find(1) = 1 a[1]=find(a[1])=find(1)=1,更新 f [ a [ 1 ] ] = f [ 1 ] = f i n d ( a [ 1 ] + 1 ) = f i n d ( 2 ) = 2 f[a[1]] = f[1] = find(a[1]+1) = find(2) = 2 f[a[1]]=f[1]=find(a[1]+1)=find(2)=2

  2. 第二次输入 2 2 2 a [ 2 ] = f i n d ( a [ 2 ] ) = f i n d ( 2 ) = 2 a[2] = find(a[2]) = find(2) = 2 a[2]=find(a[2])=find(2)=2,更新 f [ a [ 2 ] ] = f [ 2 ] = f i n d ( a [ 2 ] + 1 ) = f i n d ( 3 ) = 3 f[a[2]] = f[2] = find(a[2]+1) = find(3) = 3 f[a[2]]=f[2]=find(a[2]+1)=find(3)=3

  3. 第三次再输入 1 1 1 a [ 3 ] = f i n d ( a [ 3 ] ) = f i n d ( 1 ) = f i n d ( 2 ) = 3 a[3] = find(a[3]) = find(1) = find(2) = 3 a[3]=find(a[3])=find(1)=find(2)=3, 这时候 a [ 3 ] a[3] a[3] 便等于 3 3 3 了。

这种查询的时间复杂度仅为 O ( l o g n ) O( logn) O(logn)。整体时间复杂度 O ( n ∗ l o g n ∗ l o g n ) O(n*logn*logn) O(nlognlogn)

#include 
using namespace std;

const int maxn = 1e6+10;

int a[maxn], f[maxn];

int find(int x)
{
	if(f[x]==x)	return x;
	else	return f[x] = find(f[x]);
}

int main()
{
	for(int i = 1; i <= maxn; i++)		//初始化f数组为它本身 
		f[i] = i;
	
	int n;
	scanf("%d", &n);
	
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &a[i]);
		a[i] = find(a[i]);				//直接把这个数变成他的父亲 
		f[a[i]] = find(a[i]+1);
	}
	
	for(int i = 1; i <= n; ++i)
		printf("%d ", a[i]);
	return 0;
}

你可能感兴趣的:(并查集)