首先,來構造這棵樹的形態c++
稱位數相同的點爲一類點,從每一類點中任選一個點,具備如下性質:網絡
1.每一類中選出的點的導出子圖連通(是一顆樹)ide
2.每一條邊必然有一個端點屬於某一類中選出的點spa
(關於「如有解,必定存在上述這種形式的解」的證實可能比較困難,大概感性理解一下?)it
因爲類別不多(記爲$m=\lfloor\log_{10}n\rfloor+1$),$o(m^{m-2})$或$o{\frac{(m+1)m}{2}\choose m-1}$暴力肯定這$m$類點中選出的點的樹形態(實際差不了多少),接下來每一條邊至關於能夠使邊端點中的一類未在連通塊中加入連通塊,即若是記$s_{x}$表示$x$類點剩餘的點數量,以後每一條邊至關於選擇$s_{x}$或$s_{y}$減少1class
很明顯是一個網絡流的模型,判一下是否滿流便可,複雜度大概可過queue
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\n",ansE[i].fi,ansE[i].se); 122 } 123 }