显然我们可以从每种长度中选出来一个点,使得其它点都连向它们,且他们之间相互连通。
首先考虑什么情况下会无解。设 \(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;
}