题目
思路
有两个很强的限制:
- 。注意这里是严格小于!所以长度至少为 。
- 。也就是说,每个“片段”是 各个前缀 的一部分。
第二个条件会是可爱的突破口。显然,如果我们知道每一个前缀,那么就能完整确定这个序列。虽然“片段”只是前缀中的一部分,也很不错了。那么我们枚举第一个前缀吧!也就是 第一个元素。
知道了前缀 ,怎么确定下一位?用已知的“片段”。如果一个“片段”中,它只有一个元素还没有出现,并且剩下的元素都出现在最靠后的部分,那么我们有理由相信,这个“片段”是前缀 的一部分。所以这个唯一的元素当然是第 个元素啦!
正确性是显然的,上面的构造方法保证了每一个“片段”都被满足。又因为第一条,对于正确的序列,只剩一个元素的前缀只有一个。
复杂度分为三部分,枚举第一个元素、逐位确定、查看“片段”。分别是 和 。总复杂度 ,很难跑满,因为中途就会因为找不到下一位元素而退出。
代码
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int_;
inline int_ readint(){
int_ a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
const int MaxN = 205;
int a[MaxN][MaxN], n;
void input(){
n = readint();
for(int i=1; i<n; ++i){
a[i][0] = readint();
for(int j=1; j<=a[i][0]; ++j)
a[i][j] = readint();
}
}
int ans[MaxN], id[MaxN];
void solve(){
for(int o=1; o<=n; ++o){ // 枚举开头
for(int i=1; i<=n; ++i)
id[i] = 0, ans[i] = 0; // clear
ans[1] = o, id[o] = 1;
for(int i=2; i<=n; ++i){
for(int j=1; j<n; ++j){
int cnt = a[j][0], x = -1;
for(int k=1; k<=a[j][0]; ++k)
if(i-a[j][0] < id[a[j][k]])
-- cnt;
else if(!id[a[j][k]])
x = a[j][k];
if(cnt == 1 && ~x){
ans[i] = x, id[x] = i; break;
}
}
if(ans[i] == 0) break; // 找不到
}
if(ans[n] != 0) break; // 找到解了
}
// printf("ANS: ");
for(int i=1; i<=n; ++i)
printf("%d ",ans[i]);
putchar('\n');
}
int main(){
for(int T=readint(); T; --T)
input(), solve();
return 0;
}