[CF611H] New Year and Forgotten Tree 题解

显然我们可以从每种长度中选出来一个点,使得其它点都连向它们,且他们之间相互连通。

首先考虑什么情况下会无解。设 \(e_{i,j}\) 表示长度为 \(i\) 的数和长度为 \(j\) 的数间连的边数还有几条没用,\(d_i\) 表示长度为 \(i\) 的数还剩几个。可以证明,当且仅当存在一个点集 \(S\),满足 \(\sum\limits_{i\in S}d_i\le\sum\limits_{i\in S,j\in S}e_{i,j}\) 时,原图无解。

所以我们每次暴力搜索加哪种边,加完后合不合法即可。

时间复杂度 \(O(2^ww^2n)\),其中 \(w\) 代表最大位数。

#include<bits/stdc++.h>
using namespace std;
int n,a[6][6],b[6],c[6],mn[6],m,mx;
string s;vector<pair<int,int> >g;
int wei(int x){
	return (int)log10(x);
}int check(){
	for(int i=0;i<(1<<(mx+1));i++){
		int sum=0,sm=0;
		for(int j=0;j<=mx;j++)
			if((i>>j)&1) sum+=b[j];
		for(int j=0;j<=mx;j++) if((i>>j)&1)
			for(int k=0;k<=mx;k++) if((i>>k)&1) sm+=a[j][k];
		if(sm>=sum&&sum) return 0;
	}return 1;
}int get(){
	for(int i=0;i<=mx;i++)
		for(int j=0;j<=mx;j++){
			if(!a[i][j]) continue;
			a[i][j]--,b[i]--;if(b[i]&&check())
				return g.push_back({mn[i]+b[i],mn[j]}),1;
			b[i]++,b[j]--;if(b[j]&&check())
				return g.push_back({mn[i],mn[j]+b[j]}),1;
			a[i][j]++,b[j]++;
		}
	return 0;
}int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n,m=n-1,mn[0]=1,mx=wei(n);
	for(int i=1;i<=n;i++) b[wei(i)]++;
	for(int i=1;i<=mx;i++) mn[i]=mn[i-1]*10;
	for(int i=1,x,y;i<n;i++)
		cin>>s,x=s.size(),cin>>s,y=s.size(),a[x-1][y-1]++;
	if(!check()) cout<<-1,exit(0);
	while(get()) m--;
	for(int i=0;i<=mx;i++)
		for(int j=0;j<=mx;j++) if(a[i][j])
			g.push_back({mn[i],mn[j]}),m--;
	if(m) cout<<-1,exit(0);
	for(auto x:g) cout<<x.first<<" "<<x.second<<"\n";
	return 0;
} 
posted @ 2025-03-11 09:08  长安一片月_22  阅读(18)  评论(0)    收藏  举报