首先,来构造这棵树的形态
称位数相同的点为一类点,从每一类点中任选一个点,具有以下性质:
1.每一类中选出的点的导出子图连通(是一颗树)
2.每一条边必然有一个端点属于某一类中选出的点
(关于“若有解,一定存在上述这种形式的解”的证明可能比较困难,大概感性理解一下?)
由于类别很少(记为$m=lfloorlog_{10}n floor+1$),$o(m^{m-2})$或$o{frac{(m+1)m}{2}choose m-1}$暴力确定这$m$类点中选出的点的树形态(实际差不了多少),接下来每一条边相当于可以使边端点中的一类未在连通块中加入连通块,即如果记$s_{x}$表示$x$类点剩余的点数量,之后每一条边相当于选择$s_{x}$或$s_{y}$减小1
很明显是一个网络流的模型,判一下是否满流即可,复杂度大概可过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define M 7 5 #define oo 0x3f3f3f3f 6 #define fi first 7 #define se second 8 struct ji{ 9 int nex,to,len; 10 }edge[M*M*M]; 11 queue<int>q; 12 vector<pair<int,int> >ansE; 13 int V,E,n,m,head[M*M],len[N],a[M][M],id[M][M],tot[M],pos[M],now[M],f[M],d[M*M],work[M*M]; 14 char s1[M],s2[M]; 15 int find(int k){ 16 if (k==f[k])return k; 17 return find(f[k]); 18 } 19 void add(int x,int y,int z){ 20 edge[E].nex=head[x]; 21 edge[E].to=y; 22 edge[E].len=z; 23 head[x]=E++; 24 if (E&1)add(y,x,0); 25 } 26 bool bfs(){ 27 memset(d,oo,sizeof(d)); 28 d[0]=0; 29 q.push(0); 30 while (!q.empty()){ 31 int k=q.front(); 32 q.pop(); 33 for(int i=head[k];i!=-1;i=edge[i].nex) 34 if ((edge[i].len)&&(d[edge[i].to]==oo)){ 35 d[edge[i].to]=d[k]+1; 36 q.push(edge[i].to); 37 } 38 } 39 return d[V+m+1]<oo; 40 } 41 int dfs(int k,int s){ 42 if (k>V+m)return s; 43 for(int &i=work[k];i!=-1;i=edge[i].nex) 44 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 45 int p=dfs(edge[i].to,min(s,edge[i].len)); 46 if (p){ 47 edge[i].len-=p; 48 edge[i^1].len+=p; 49 return p; 50 } 51 } 52 return 0; 53 } 54 int dinic(){ 55 int k,ans=0; 56 while (bfs()){ 57 memcpy(work,head,sizeof(work)); 58 while (k=dfs(0,oo))ans+=k; 59 } 60 return ans; 61 } 62 bool dfs(int k,int x,int y){ 63 if (k>=m){ 64 E=0; 65 memset(head,-1,sizeof(head)); 66 for(int i=1;i<=m;i++) 67 for(int j=i;j<=m;j++){ 68 add(0,id[i][j],a[i][j]); 69 add(id[i][j],V+i,oo); 70 add(id[i][j],V+j,oo); 71 } 72 for(int i=1;i<=m;i++)add(V+i,V+m+1,tot[i]); 73 if (dinic()==n-m){ 74 for(int i=1;i<=m;i++) 75 for(int j=i;j<=m;j++) 76 for(int k=head[id[i][j]];k!=-1;k=edge[k].nex) 77 if (edge[k].to>V){ 78 int p=edge[k].to-V; 79 for(int l=edge[k].len;l<oo;l++)ansE.push_back(make_pair(++now[p],pos[i+j-p])); 80 } 81 return 1; 82 } 83 return 0; 84 } 85 for(int i=x;i<=m;i++) 86 for(int j=y;j<=m;j++) 87 if ((a[i][j])&&(find(i)!=find(j))){ 88 int ii=find(i); 89 f[ii]=j; 90 a[i][j]--; 91 ansE.push_back(make_pair(pos[i],pos[j])); 92 if (dfs(k+1,i,j))return 1; 93 f[ii]=ii; 94 a[i][j]++; 95 ansE.pop_back(); 96 } 97 return 0; 98 } 99 int main(){ 100 scanf("%d",&n); 101 for(int i=1;i<n;i++){ 102 scanf("%s%s",s1,s2); 103 int x=strlen(s1),y=strlen(s2); 104 if (x>y)swap(x,y); 105 a[x][y]++; 106 } 107 for(int i=1;i<=n;i++){ 108 len[i]=len[i/10]+1; 109 tot[len[i]]++; 110 } 111 m=len[n]; 112 for(int i=1;i<=m;i++)tot[i]--; 113 pos[1]=1; 114 for(int i=2;i<=m;i++)pos[i]=pos[i-1]*10; 115 memcpy(now,pos,sizeof(now)); 116 for(int i=1;i<=m;i++)f[i]=i; 117 for(int i=1;i<=m;i++) 118 for(int j=i;j<=m;j++)id[i][j]=++V; 119 if (!dfs(1,1,1))printf("-1"); 120 else{ 121 for(int i=0;i<ansE.size();i++)printf("%d %d ",ansE[i].fi,ansE[i].se); 122 } 123 }