Gym - 101755F F. Tree Restoration

F. Tree Restoration
time limit per test
2.0 s
memory limit per test
256 MB
input
standard input
output
standard output

There is a tree of n vertices. For each vertex a list of all its successors is known (not only direct ones). It is required to restore the tree or to say there is no such tree.

Input

The first line contains a single integer n (1 ≤ n ≤ 1000) — the number of vertices in the tree.

Each of the next n lines contains an integer ci (0 ≤ ci ≤ n) — the number of successors of vertex i, and then ci distinct integers aij(1 ≤ aij ≤ n) — the indices of successors of vertex i.

Output

If the answer does not exist, output «NO».

Otherwise, in the first line output «YES», and then output n - 1 lines containing two integers each — indices of parent and child. Pairs (parent, child) can be output in any order.

Examples
input
Copy
5
4 2 3 4 5
3 3 4 5
2 4 5
1 5
0
output
Copy
YES
1 2
2 3
3 4
4 5
input
Copy
5
4 2 3 4 5
3 3 4 5
0
1 5
0
output
Copy
YES
1 2
2 3
2 4
4 5
input
Copy
3
3 2 3 1
3 3 1 2
3 1 2 3
output
Copy
NO

题意:   给你n 个点和他的后继元素 (不一定是他的儿子 有可能是孙子等等 )  你的目标 就是要求出是否能够存在一棵树,然后满足给你的数据,如果满足输出这棵树,不满足输出NO  。

思路: 连一下边 可以想到用拓扑排序去处理,但是比较坑的一个点就是  如果两个元素的后继是相同的,  但是拓扑排序建出的树就不一定是 满足条件的。

样例 :

5

4 2 3 4 5

2 4 5

2 4 5

0

0

所以在用拓扑建出树之后再还原一下原本的图,看是否一样。

代码: 

#include<bits/stdc++.h>
#define N 1005

using namespace std;

int inde[N];
int n;
vector< int >ve[N],tree[N],huan[N];


void dfs(int u){
	int sz=ve[u].size();
	
	for(int i=0;i<sz;i++){
		int v=ve[u][i];
		dfs(v);
		huan[u].push_back(v);
		int sz1=huan[v].size();
		for(int j=0;j<sz1;j++){
			huan[u].push_back(huan[v][j]);
		}
	}
	
	return ;
}

int main()
{
	int c,x;
	
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&c);
		while(c--){
			scanf("%d",&x);
			inde[x]++;
			tree[i].push_back(x);
		}
	}
	
	    int in;
		int cc=0;
		for(int i=1;i<=n;i++){
			if(inde[i]==0){
				cc++;
				in=i;
			}
		}
		
		if(cc>=2||cc==0){
			printf("NO\n");
			return 0;
		}
		
		queue< int >que;
		que.push(in);
		int f=0;
		int cnt=0;
		while( !que.empty() ){
			int u=que.front();  cnt++;  que.pop();
			
			int sz=tree[u].size();
			for(int i=0;i<sz;i++){
				int v=tree[u][i];
				inde[v]--;
				if(inde[v]==0){
					que.push(v);
					ve[u].push_back(v);
				}
			}
		}
		
		if( cnt!=n ) {
			printf("NO\n");
			return 0;
		}
		
		dfs(in);
		/*
		for(int i=1;i<=n;i++){
			int sz=huan[i].size();
			for(int j=0;j<sz;j++){
				printf("%d ",huan[i][j]);
			}
			cout<<endl;
		}*/
		
		for(int i=1;i<=n;i++){
			sort(tree[i].begin(),tree[i].end());
			sort(huan[i].begin(),huan[i].end());
			
			int sz=tree[i].size();  int sz1=huan[i].size();
			if(sz!=sz1){
				printf("NO\n");
				return 0;
			}
			for(int j=0;j<sz;j++){
				if(tree[i][j]!=huan[i][j]){
					printf("NO\n");
					return 0;
				}
			}
			
		}
		
		printf("YES\n");
		
		for(int i=1;i<=n;i++){
			int sz=ve[i].size();
			for(int j=0;j<sz;j++){
				printf("%d %d\n",i,ve[i][j]);
			}
		}
	
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值