题解 AT4505 【[AGC029F] Construction of a tree】
AGC 029F
Solution
神仙构造题。
考虑如何才能构成一颗树,显然有一个必要条件是对于每个点
实际上这个条件也是充分的,证明考虑如下的构造算法:首先将
时间复杂度
Code
int n,tot,S,T;
int p[MAXN];
pii ans[MAXN];
vector<int> G[MAXN];
namespace NetWorkFlow{
int len,maxFlow;
int head[MAXN],cur[MAXN],dep[MAXN],vis[MAXN];
queue<int> q;
struct Edge{
int to,next,flow;
} e[MAXM];
void Init(){
memset(head,-1,sizeof(head));
len = 1;
}
void add_edge(int u,int v,int flow){
e[++len] = (Edge){v,head[u],flow};
head[u] = len;
e[++len] = (Edge){u,head[v],0};
head[v] = len;
}
int bfs(){
for(int i = 0;i <= tot;i++){
cur[i] = head[i];
dep[i] = -1;
}
dep[S] = 0;
q.push(S);
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = head[u];i != -1;i = e[i].next){
int v = e[i].to;
if(dep[v] == -1 && e[i].flow){
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[T] != -1;
}
int dfs(int u,int flow){
if(u == T){
maxFlow += flow;
return flow;
}
int used = 0,low;
for(int i = cur[u];i != -1;i = e[i].next){
cur[u] = i;
int v = e[i].to;
if(dep[v] == dep[u] + 1 && e[i].flow){
if(low = dfs(v,min(flow - used,e[i].flow))){
e[i].flow -= low;
e[i ^ 1].flow += low;
used += low;
if(used == flow)
break;
}
}
}
return used;
}
int Dinic(){
while(bfs()) dfs(S,INF);
return maxFlow;
}
bool GetAns(){
for(int u = 2;u <= n;u++){
for(int i = head[u];i != -1;i = e[i].next){
int v = e[i].to;
if(v != S && !e[i].flow) p[v - n] = u;
}
}
q.push(1);
int cnt = 0;
while(!q.empty()){
int u = q.front();
q.pop();
for(int v : G[u]){
if(!vis[v]){
ans[v] = make_pair(u,p[v]);
cnt += 1;
q.push(p[v]);
vis[v] = 1;
}
}
}
return cnt == n - 1;
}
}
int main(){
NetWorkFlow::Init();
scanf("%d",&n);
S = 1;
for(int i = 2;i <= n;i++)
NetWorkFlow::add_edge(S,i,1);
for(int i = 1,x,y;i < n;i++){
scanf("%d",&x);
while(x--){
scanf("%d",&y);
if(y != 1) NetWorkFlow::add_edge(y,i + n,1);
G[y].push_back(i);
}
}
tot = T = n + n;
for(int i = 1;i < n;i++)
NetWorkFlow::add_edge(i + n,T,1);
if(NetWorkFlow::Dinic() < n - 1){
puts("-1");
return 0;
}
if(!NetWorkFlow::GetAns()){
puts("-1");
return 0;
}
for(int i = 1;i < n;i++)
printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}