/* 先定一个结尾:只出现一次的都可以当成结尾,然后把结尾所在的集合影响删掉,继续往前找 找完一整个序列后还要再和给定的序列比较一下看是不是满足要求 注意前两个数要特判,第一个数肯定比第二个数出现次数少 */ #include<bits/stdc++.h> using namespace std; #define N 505 int vis[N],n,cnt[N]; set<int>s[N],ss[N]; vector<int>ans; struct Node{ int c,f,id;//出现次数,在上一个数组中是否出现过 }p[N]; int cmp(Node a,Node b){ if(a.c==b.c)return a.f>b.f; return a.c<b.c; } int pos; int solve(int end){ pos=0; ans.clear(); memset(p,0,sizeof p); memset(vis,0,sizeof vis); int num=end,now; for(int i=1;i<=n;i++) p[i].c=cnt[i],p[i].f=0,p[i].id=i; ans.push_back(num);p[num].c=100000; for(int i=2;i<=n;i++) if(s[i].find(num)!=s[i].end()) now=i,vis[i]=1; ss[++pos]=s[now]; for(auto x:s[now])p[x].c--,p[x].f=1; for(int i=1;i<=n-2;i++){ sort(p+1,p+1+n,cmp); //按出现次数排序 int tmp[N]; for(int j=1;j<=n;j++)tmp[p[j].id]=j; if(p[1].c!=1)return 0; if(p[1].f==0)return 0; num=p[1].id; ans.push_back(num);p[tmp[num]].c=100000; now=-1; for(int j=2;j<=n;j++) if(!vis[j] && s[j].find(num)!=s[j].end()) now=j,vis[j]=1; if(now==-1)return 0; for(int j=1;j<=n;j++)p[j].f=0; for(auto x:s[now])p[tmp[x]].c--,p[tmp[x]].f=1; } for(int i=1;i<=n;i++) if(p[i].c==0)ans.push_back(p[i].id); if(ans.size()!=n)return 0; int i=0,j=ans.size()-1; while(i<j) swap(ans[i],ans[j]),i++,j--; if(cnt[ans[0]]>cnt[ans[1]])swap(ans[0],ans[1]); if(ans.size()==n)return 1; for(int i=2;i<=n;i++){ set<int>t; for(int j=i-ss[i].size()+1;j<=i-1;j++) t.insert(ans[j]); if(t!=ss[i])return 0; } return 0; } int main(){ int t;cin>>t; while(t--){ memset(cnt,0,sizeof cnt); cin>>n; for(int i=1;i<=n;i++)s[i].clear(); for(int i=2;i<=n;i++){ int k,x;scanf("%d",&k); while(k--){ scanf("%d",&x); s[i].insert(x); cnt[x]++; } } for(int i=1;i<=n;i++)if(cnt[i]==1){ int res=solve(i); if(res)break; } for(int i=0;i<ans.size();i++) cout<<ans[i]<<" "; puts(""); } }