[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;
}

浙公网安备 33010602011771号