[atAGC029F]Construction of a tree
构造一张二分图,左边是$n$个点,右边是$n-1$个集合,按照点属于集合连边
定义一组匹配的意义,即说明该点的父亲在该集合中选择
利用dinic求出二分图的最大匹配,若不为$n-1$则无解,否则考虑如何去构造一组解:
考虑左边剩下的未参与匹配的点$x$,将其作为根,并将所有含有$x$的集合所匹配的点都作为$x$的儿子,重复此过程(对于其他点,要加上一个“未被选择过”)
事实上,这个过程可以看作从源点出发在残余网络上的一棵bfs树,合法当且仅当能bfs到所有点
(能从$x$走到对应集合当且仅当其匹配的不是该集合,能从一个集合走到$y$当且仅当$y$匹配了该集合,同时$y$一定不会去选择其所匹配的集合中的点,因为一定被其父亲选择完毕)
下面,我们来证明若某一种匹配方式不能做到,则其余都不行:
由于根是任意的,换言之这个点作为根如果不行,其余点也都不行,因此确定了根
考虑调整匹配方案,一定可以通过若干次对一个序列的循环(通过将调整建为一张图可以证明)
若轮换前这一个集合中存在一个点能被搜到,按照轮换的顺序其余点都能被搜到,因此轮换前所有点都不能被搜到,即是一个内部的交换,没有意义
总复杂度为$o(n\sqrt{n})$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define oo 0x3f3f3f3f 5 struct ji{ 6 int nex,to,len; 7 }edge[N<<3]; 8 queue<int>q; 9 pair<int,int>ans[N]; 10 int E,n,x,y,tot,head[N<<1],work[N<<1],d[N<<1]; 11 void add(int x,int y,int z){ 12 edge[E].nex=head[x]; 13 edge[E].to=y; 14 edge[E].len=z; 15 head[x]=E++; 16 if (E&1)add(y,x,0); 17 } 18 bool bfs(){ 19 memset(d,oo,sizeof(d)); 20 d[0]=0; 21 q.push(0); 22 while (!q.empty()){ 23 int k=q.front(); 24 q.pop(); 25 for(int i=head[k];i!=-1;i=edge[i].nex) 26 if ((edge[i].len)&&(d[edge[i].to]==oo)){ 27 d[edge[i].to]=d[k]+1; 28 q.push(edge[i].to); 29 } 30 } 31 return d[2*n]<oo; 32 } 33 int dfs(int k,int s){ 34 if (k==2*n)return s; 35 for(int &i=work[k];i!=-1;i=edge[i].nex) 36 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){ 37 int p=dfs(edge[i].to,min(s,edge[i].len)); 38 if (p){ 39 edge[i].len-=p; 40 edge[i^1].len+=p; 41 return p; 42 } 43 } 44 return 0; 45 } 46 int dinic(){ 47 int k,ans=0; 48 while (bfs()){ 49 memcpy(work,head,sizeof(work)); 50 while (k=dfs(0,oo))ans+=k; 51 } 52 return ans; 53 } 54 void bfs_build(){ 55 memset(d,0,sizeof(d)); 56 for(int i=head[0];i!=-1;i=edge[i].nex) 57 if (edge[i].len){ 58 q.push(edge[i].to); 59 d[edge[i].to]=edge[i].to; 60 } 61 while (!q.empty()){ 62 int k=q.front(); 63 q.pop(); 64 for(int i=head[k];i!=-1;i=edge[i].nex) 65 if ((edge[i].to)&&(edge[i].len)&&(!d[edge[i].to])){ 66 if (edge[i].to>n)d[edge[i].to]=d[k]; 67 else{ 68 tot++; 69 ans[k-n]=make_pair(d[k],edge[i].to); 70 d[edge[i].to]=edge[i].to; 71 } 72 q.push(edge[i].to); 73 } 74 } 75 } 76 int main(){ 77 scanf("%d",&n); 78 memset(head,-1,sizeof(head)); 79 for(int i=1;i<=n;i++)add(0,i,1); 80 for(int i=1;i<n;i++){ 81 scanf("%d",&x); 82 add(i+n,2*n,1); 83 for(int j=1;j<=x;j++){ 84 scanf("%d",&y); 85 add(y,i+n,1); 86 } 87 } 88 if (dinic()<n-1){ 89 printf("-1"); 90 return 0; 91 } 92 bfs_build(); 93 if (tot!=n-1)printf("-1"); 94 else{ 95 for(int i=1;i<n;i++) 96 printf("%d %d\n",ans[i].first,ans[i].second); 97 } 98 }