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

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

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

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

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

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

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

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

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

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

总复杂度为$o(n\sqrt{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\n",ans[i].first,ans[i].second);
97 }
98 }

[atAGC029F]Construction of a tree的更多相关文章

  1. @atcoder - AGC029F@ Construction of a tree

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定 N - 1 个 {1, 2, ..., N} 的子集,第 ...

  2. AT4505-[AGC029F]Construction of a tree【构造题,hall定理,网络流】

    正题 题目链接:https://www.luogu.com.cn/problem/AT4505 题目大意 给出\(n\)个点和\(n-1\)个点集\(U_i\),每个点集中选择两个点连边使得该图是一棵 ...

  3. phylogeny analysis

    Multiple Alignment: MUSCLE ProbCons T-Coffee ClustalW Alignment curation: Gblocks Remove positions w ...

  4. 【AtCoder】AGC029(A-E)

    A - Irreversible operation 题解 把每个B后面的W个数累加起来即可 代码 #include <bits/stdc++.h> #define fi first #d ...

  5. JS进阶 - 浏览器工作原理

    一.浏览器的结构 浏览器的主要组件为: 用户界面 - 包括地址栏.前进/后退按钮.书签菜单等.除了浏览器主窗口(显示页面),其他部分都属于用户界面. 浏览器引擎 - 在用户界面和渲染引擎之间传送指令. ...

  6. Bounding Volume Hierarchy BVH in OpenCASCADE

    Bounding Volume Hierarchy BVH in OpenCASCADE eryar@163.com Abstract. Bounding Volume Hierarchy(BVH) ...

  7. WC2021 题目清单

    Day2 上午 <IOI题型与趣题分析> 来源 题目 完成情况 备注 IOI2002 Day1T1 Frog 已完成 IOI2002 Day1T2 Utopia IOI2002 Day1T ...

  8. 数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction

    Tree Construction Problem's Link ------------------------------------------------------------------- ...

  9. STL---Codeforces675D Tree Construction(二叉树节点的父亲节点)

    Description During the programming classes Vasya was assigned a difficult problem. However, he doesn ...

随机推荐

  1. 11.4.5 LVS负载均衡常见工作模式总结以及ipvsadm

      NAT TUN DR RS any Tunneling Non-arp device RS network private LAN/WAN LAN RS number low(10-20) Hig ...

  2. 调试器地址出现大小端紊乱,引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突。

    今天在编写一系列新增需求代码后,开始调试代码 发现上个版本正常可运行的代码出现了:引发的异常: 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问冲突. 上个版本数代码 ...

  3. 【分享】 一款自用的Anki卡片模板:黄子涵单词卡片 v1

    [分享] 一款自用的Anki卡片模板:黄子涵单词卡片 v1 说明 第一代的功能 主要有两部分组成:英文和含义,目前主要是为自己记忆Web前端一些常用的单词而服务 有美美哒背景图,本来想修改为随机背景图 ...

  4. 使用CSS选择器(第二部分)

    伪类跟伪元素一样,并不是直接针对文档元素的,而是为你基于某些共同特征选择元素提供方便. 使用结构性伪类选择器 使用结构性伪类选择器能够根据元素在文档中的位置选择元素.这类选择器都有一个冒号字符前缀(: ...

  5. 详解build-gradle文件

    目录 gradle 两个build.gradle文件 最外层目录下的build.gradle文件 jcenter dependencies闭包 app目录下的build.gradle文件 com.an ...

  6. Netty 了解

    1.1 Netty 是什么? Netty is an asynchronous event-driven network application framework for rapid develop ...

  7. Google Style Guides

    Google Style Guides Google Style Guides Google 开源项目风格指南 (zh-google-styleguide.readthedocs.io)

  8. sql常用的统计公式

    hivesql中max,min函数不能作用于多列,因此在有上下门限区间限制时多用公式直接计算. max(x,y)=(x+y+ABS(x-y))/2 min(x,y)=(x+y-ABS(x-y))/2 ...

  9. javascript-jquery介绍

    jquery优势 1.轻量级 2.强大的选择器 3.出色的DOM封装 4.可靠的事件处理机制 5.完善的Ajax 6.不污染顶级变量 7.出色的浏览器兼容 8.链式操作方式 9.隐式迭代 10.行为层 ...

  10. Spring Security Jwt Token 自动刷新

    token的自动刷新 一.功能需求 二.功能分析 1.token 的生成 2.token 的自动延长 3.系统资源的保护 4.用户如何传递 token 三.实现思路 1.生成 token 和 refr ...