Restore the Permutation by Sorted Segments CodeForces - 1343F(暴力+Set+Vector)

We guessed a permutation p consisting of n integers. The permutation of length n is the array of length n where each element from 1 to n appears exactly once. This permutation is a secret for you.

For each position r from 2 to n we chose some other index l (l<r) and gave you the segment pl,pl+1,…,pr in sorted order (i.e. we rearranged the elements of this segment in a way that the elements of this segment are sorted). Thus, you are given exactly n−1 segments of the initial permutation but elements inside each segment are sorted. The segments are given to you in random order.

For example, if the secret permutation is p=[3,1,4,6,2,5] then the possible given set of segments can be:

[2,5,6]
[4,6]
[1,3,4]
[1,3]
[1,2,4,6]
Your task is to find any suitable permutation (i.e. any permutation corresponding to the given input data). It is guaranteed that the input data corresponds to some permutation (i.e. such permutation exists).

You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤100) — the number of test cases. Then t test cases follow.

The first line of the test case contains one integer n (2≤n≤200) — the length of the permutation.

The next n−1 lines describe given segments.

The i-th line contains the description of the i-th segment. The line starts with the integer ki (2≤ki≤n) — the length of the i-th segment. Then ki integers follow. All integers in a line are distinct, sorted in ascending order, between 1 and n, inclusive.

It is guaranteed that the required p exists for each test case.

It is also guaranteed that the sum of n over all test cases does not exceed 200 (∑n≤200).

Output
For each test case, print the answer: n integers p1,p2,…,pn (1≤pi≤n, all pi should be distinct) — any suitable permutation (i.e. any permutation corresponding to the test case input).

Example
Input
5
6
3 2 5 6
2 4 6
3 1 3 4
2 1 3
4 1 2 4 6
5
2 2 3
2 1 2
2 1 4
2 4 5
7
3 1 2 6
4 1 3 5 6
2 1 2
3 4 5 7
6 1 2 3 4 5 6
3 1 3 6
2
2 1 2
5
2 2 5
3 2 3 5
4 2 3 4 5
5 1 2 3 4 5
Output
3 1 4 6 2 5
3 2 1 4 5
2 1 6 3 5 4 7
1 2
2 5 3 4 1
题意:一个数组,是n个数的一个排列。给定n-1的序列,这些序列的坐标是[l,r],其中l是未知的,但是r呢,是[2,n]每一个位置都有(但是不确定哪一组数的r是多少),要求我们还原原序列。
思路:这个题目,n只有200,很奇特,暗示我们可以暴力去做。还有一个独特之处就是r的范围严格是属于[2,n]的,那么肯定有一组序列是2个,并且这组序列是原序列的1,2位置。那么我们把第一个数找出来,然后在其他序列中删去第一个数,那么剩下的元素个数为一的序列中的那个数,就是第二个数了,依次这样找下去。那么我们怎么确定第一个数呢?只能枚举了。
需要注意的是,如果元素个数为一的序列不为1(多于1或者少于1)就说明这样找是不正确的。
如果按照上面的方式找到一组序列,别着急输出,还要检测是否和题目给定的序列一样(针对第一个样例),如果含有n-1组序列和题目给定的序列一样的话,就说明是正确的。
主要用到了set和vector。这道题目再一次证明了set的强大性。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=2e2+100;
set<int> s[maxx];
vector<set<int> >p,q;
vector<int> ans;
int n;

inline void init()
{
	for(int i=1;i<=n;i++) s[i].clear();
	p.clear(),q.clear();
}
inline bool check()
{
	set<set<int> >s;
	for(int i=0;i<p.size();i++) s.insert(p[i]);
	for(int i=0;i<n;i++)
	{
		set<int> ss;
		ss.insert(ans[i]);
		for(int j=i+1;j<n;j++)
		{
			ss.insert(ans[j]);
			if(s.count(ss)) s.erase(ss);
		}
	}
	return s.empty();
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		init();
		int x,y;
		for(int i=1;i<n;i++)
		{
			scanf("%d",&x);
			for(int j=1;j<=x;j++)
			{
				scanf("%d",&y);
				s[i].insert(y);
			}
			p.push_back(s[i]);
		}
		
		for(int i=1;i<=n;i++)
		{
			ans.clear();
			ans.push_back(i);
			q=p;
			for(int j=0;j<q.size();j++) if(q[j].count(i)) q[j].erase(i);
			int flag=1;
			while(flag&&ans.size()<n)
			{
				int num=0;
				int pos;
				for(int j=0;j<q.size();j++) if(q[j].size()==1) num++,pos=j;
				if(num>1||num<1) 
				{
					flag=0;
					break;
				}
				int tt=*q[pos].begin();
				ans.push_back(tt);
				for(int j=0;j<q.size();j++) if(q[j].count(tt)) q[j].erase(tt);
			}
			if(flag&&check()) break;
		}
		for(int i=0;i<ans.size();i++) cout<<ans[i]<<" ";
		cout<<endl;
	}
	return 0;
}

努力加油a啊,(o)/~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值