题意:
现在有一个长度为n的排列,然后有n-1个序列,每个序列是对应源排列的某一个子串的排序,每个序列的长度>=2,并且每个序列在源排列中的右端点不同。让你构造源排列。
题解:
它的数据范围很小,那么首先看能不能暴力,由于每个序列的右端点都是不同的,所以至少会有一个长度为2的序列,所以如果知道了第一个点,那么就能知道第二个点,那么就能知道第三个点。。。以此类推。所以只需要枚举开头即可。
首先枚举开头,那么如果有它在某一个序列中并且这个序列的长度为2,他就有可能是答案。知道了开头以后,我们需要知道每一个序列的状态,也就是说这个序列是否包含当前的数,
vec装的是已确定的数
stg等于0的时候就表示从开头到现在还没有任意一个数出现在这个串里,
stg=2表示这个序列的所有数都在之前确定下来的数中
stg=1表示这个序列有部分在已确定的数中,有部分不在
做n-1遍接下来的操作:
for一遍所有的序列,如果当前序列的状态为2,就跳过
如果当前的序列状态为1且当前的数不在这个序列中,就表示现在我们做的结果有问题,返回
如果当前的序列包括当前的值,那么首先把这个序列置为1,然后删掉当前值,那么如果这个序列的大小为1,说明接下来的值就是这个序列中剩下的元素
如果这个序列大小为0,就将这个序列的状态置为2
那么为什么状态为1且不再序列中就是错的,因为这个序列在原串中是连续的,如果这个序列的状态为1就表示我们现在的值就一定在这个序列中才对。
#include<bits/stdc++.h>
using namespace std;
const int N=205;
unordered_set<int>s[N],tmp[N];
int stg[N];
int n;
vector<int>vec;
int check(int sta){
memset(stg,0,sizeof(stg));
vec.clear();
vec.push_back(sta);
int ne;
for(int i=2;i<=n;i++){
for(int j=2;j<=n;j++){
if(stg[j]==2)continue;
if(stg[j]==1&&!tmp[j].count(sta))return 0;
if(tmp[j].count(sta)){
stg[j]=1;
tmp[j].erase(sta);
if(tmp[j].size()==1)
ne=*tmp[j].begin();
if(tmp[j].size()==0)
stg[j]=2;
}
}
sta=ne;
vec.push_back(sta);
}
for(auto i:vec)printf("%d ",i);
printf("\n");
return 1;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=2;i<=n;i++){
s[i].clear();
int k,x;
scanf("%d",&k);
while(k--)
scanf("%d",&x),s[i].insert(x);
}
for(int i=1;i<=n;i++){
int f=0;
for(int j=2;j<=n;j++){
if(s[j].count(i)&&s[j].size()==2){
f=1;
break;
}
}
if(f){
for(int j=2;j<=n;j++)
tmp[j]=s[j];
if(check(i))break;
}
}
}
return 0;
}