AGC029F Construction of a tree

Link
我们把每个集合看做左部点,每个数看做右部点,一个集合和这个集合中的数连边,那么可以构成一个二分图。
我们把这棵树任选一个点作为根,让每个集合匹配这条边两端中深度较大的那个点,那么就会得到一个去掉根之后的完美匹配。
注意到这是一个无根树,所以我们必须满足去掉任意一个右部点,这个二分图都有完美匹配。
不难发现这个条件也是充分的。
先求出一个完美匹配,然后从\(1\)开始在二分图上bfs,如果图不连通那么说明无解。bfs的时候可以顺便把方案构造了。

#include<queue>
#include<cstdio>
#include<cctype>
const int N=100007;
std::vector<int>e[N];std::queue<int>q;
int vis[N],mat[N],tam[N];
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int dfs(int u,int root)
{
    for(int v:e[u]) if(vis[v]^root) if(vis[v]=root,!mat[v]||dfs(mat[v],root)) return mat[v]=u;
    return 0;
}
int main()
{
    int n=read();
    for(int i=1;i<n;++i) for(int j=read();j;--j) e[read()].push_back(i);
    for(int i=2;i<=n;++i) if(!dfs(i,i)) return puts("-1"),0;
    q.push(1);
    for(int i=1,u;i<=n;++i)
    {
	if(q.empty()) return puts("-1"),0;
	u=q.front(),q.pop();
	for(int v:e[u]) if(!tam[v]) tam[v]=u,q.push(mat[v]);
    }
    for(int i=1;i<n;++i) printf("%d %d\n",tam[i],mat[i]);
}
posted @ 2020-04-04 22:40  Shiina_Mashiro  阅读(142)  评论(2编辑  收藏  举报