[atAGC029F]Construction of a tree

构造一张二分图,左边是$n$个点,右边是$n-1$个集合,按照点属于集合连边

定义一组匹配的意义,即说明该点的父亲在该集合中选择

利用dinic求出二分图的最大匹配,若不为$n-1$则无解,否则考虑如何去构造一组解:

考虑左边剩下的未参与匹配的点$x$,将其作为根,并将所有含有$x$的集合所匹配的点都作为$x$的儿子,重复此过程(对于其他点,要加上一个“未被选择过”)

事实上,这个过程可以看作从源点出发在残余网络上的一棵bfs树,合法当且仅当能bfs到所有点

(能从$x$走到对应集合当且仅当其匹配的不是该集合,能从一个集合走到$y$当且仅当$y$匹配了该集合,同时$y$一定不会去选择其所匹配的集合中的点,因为一定被其父亲选择完毕)

下面,我们来证明若某一种匹配方式不能做到,则其余都不行:

由于根是任意的,换言之这个点作为根如果不行,其余点也都不行,因此确定了根

考虑调整匹配方案,一定可以通过若干次对一个序列的循环(通过将调整建为一张图可以证明)

若轮换前这一个集合中存在一个点能被搜到,按照轮换的顺序其余点都能被搜到,因此轮换前所有点都不能被搜到,即是一个内部的交换,没有意义

总复杂度为$o(nsqrt{n})$,可以通过

 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
",ans[i].first,ans[i].second);
97     }
98 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14372658.html