qoj10096 Generating Random Trees

题意

\(k\) 组询问,每组询问给出一棵 \(n\) 个点的树,这棵树可能由以下两种形式之一生成:

  1. 每次随机连接两个未连通的点。

  2. 生成所有可能的树,然后随机选择一棵树

你需要判断该树由哪种形式生成,且正确率达到 \(80\%\)

何意味

原题(加强版)[ZJOI2016] 随机树生成器

现在知道为什么这题过这么多了。

思路

观察到我们根本观察不到任何东西,因此我们直接打表,考虑找出两种生成方式的树的明显特征。

第二种生成方法显然不能枚举所有树,但是有个东西叫Prüfer 序列,即将一棵大小为 \(n\) 的树跟一个长度为 \(n-2\),元素范围为 \(1\sim n\) 的整数序列对应起来,而且每一种树都对应唯一的一个序列。所以随机一个Prüfer 序列即可表示出一种该随机方法生成的树。

于是我们急速写出找规律程序,考虑能不能从树上一些最基础的参数(如直径,重心,最大深度)等找出规律。

这里给出树的生成程序:

mt19937 rnd(time(0));
int n=10000,f[10005],p[10005],d[10005];
vector<int> t1[10005],t2[10005];
int find(int x){
	if(f[x]!=x) f[x]=find(f[x]);
	return f[x];
}
void rnd1(){
	for(int i=1;i<=n;i++)
		f[i]=i,t1[i].clear();
	int cnt=0;
	while(cnt!=n-1){
		int x=rnd()%n+1,y=rnd()%n+1;
		if(find(x)!=find(y)){
			cnt++;
			f[find(x)]=find(y);
			t1[x].push_back(y);
			t1[y].push_back(x);
		}
	}
}
void rnd2(){
	for(int i=1;i<=n;i++)
		d[i]=0,t2[i].clear();
	for(int i=1;i<=n-2;i++)
		p[i]=rnd()%n+1,d[p[i]]++;
	priority_queue<int,vector<int>,greater<int>> q;
	for(int i=1;i<=n;i++)
		if(!d[i]) q.push(i);
	for(int x,i=1;i<=n-2;i++){
		x=q.top(),q.pop(),d[p[i]]--;
		t2[x].push_back(p[i]);
		t2[p[i]].push_back(x);
		if(!d[p[i]]) q.push(p[i]);
	}
	t2[q.top()].push_back(n);
	t2[n].push_back(q.top());
}

然后我们首先从直径入手:

183 372
138 308
152 273
199 244
190 366
142 263
208 287
177 308
148 358
190 342
166 252
172 525
147 268
151 297
196 310
...

第一组为 rnd1(),第二组为 rnd2()

规律也就显而易见了,剩下的也不用试了。

直接判断树的直径是否小于 \(250\) 即可,正确率来到了惊人的 \(95\%+\)

代码

#include <bits/stdc++.h>
using namespace std;
mt19937 rnd(time(0));
int n,k;
vector<int> t1[10005];
int zj1,i1;
void dfs1(int x,int fa,int dp){
	if(dp>zj1)
		zj1=dp,i1=x;
	for(int v:t1[x])
		if(v!=fa)
			dfs1(v,x,dp+1);
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>k;
	for(int j=1;j<=2*k;j++){
		for(int i=1;i<=n;i++)
			t1[i].clear();
		for(int x,y,i=1;i<n;i++){
			cin>>x>>y;
			t1[x].push_back(y);
			t1[y].push_back(x);
		}
		zj1=i1=0;
		dfs1(1,0,0);
		dfs1(i1,0,0);
		if(zj1<=250)
			cout<<"DSU"<<endl;
		else
			cout<<"Uniform"<<endl;
	}
	return 0;
}
posted @ 2025-09-10 08:29  WuMin4  阅读(13)  评论(0)    收藏  举报