题解:显然,如果在第i行(i > 1)有一个数,那么这个数一定是被第i-1行一个比他小的数挤下来的
那么就可以从最后一行开始不断往上找比他小的数, 直到第一行,形成一个个链,最后再从第一行开始把链一个个倒着输出出来就是答案了。
如果有个数找不到链了那么说明无解
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
const int N = 100000+20;
int n,m;
vector<int> a[N];
set<int> s[N];
set<int>::iterator ite;
int pre[N];
int nxt[N];
bool vis[N];
vector<int> ans;
bool work(int l,int num){
if(l < 0)return 1;
if(s[l].size() == 0)return 0;
set<int>::iterator kte = s[l].lower_bound(num);
if(kte == s[l].begin())return 0;
kte--;
pre[num] = *kte;
nxt[*kte] = num;
s[l].erase(kte);
return 1;
//return work(l-1, *kte);
}
void gao(int num)
{
vector<int> tmp;
while(nxt[num] != -1){
vis[num] = 1;
tmp.push_back(num);
num = nxt[num];
}
vis[num] = 1;
ans.push_back(num);
for(int i = tmp.size() - 1 ;i >= 0; i --)ans.push_back(tmp[i]);
}
void solve()
{
CLR(pre,-1);
CLR(nxt,-1);
CLR(vis,0);
bool ok = 1;
ans.clear();
for(int i = m-1 ; i > 0 ; i --){
for(int j = a[i].size()-1; j >= 0 ; j--){
if(!work(i-1, a[i][j])){
ok = 0;
break;
}
}
if(!ok)break;
}
if(!ok){
puts("No solution");
}else{
for(int i = 0 ; i < m ; i ++){
for(int j = 0 ;j < a[i].size(); j ++){
if(!vis[a[i][j]]){
gao(a[i][j]);
}
}
}
for(int i = 0; i < ans.size() ; i ++){
if(i > 0)printf(" ");
printf("%d",ans[i]);
}
puts("");
}
}
int main()
{
int T,cas = 0;
scanf("%d",&T);
while(T--){
cas ++;
printf("Case #%d: ",cas);
scanf("%d%d",&n,&m);
for(int i = 0 ; i < m ; i ++)a[i].clear();
for(int i = 0 ; i < m ; i ++){
int num;
scanf("%d",&num);
while(num--){
int x;
scanf("%d",&x);
a[i].push_back(x);
}
}
bool ok = 1;
for(int i = 0 ; i < m ; i ++){
for(int j = 1 ;j < a[i].size() ;j ++){
if(a[i][j] < a[i][j-1])ok = 0;
}
}
for(int i = 0 ;i < m ;i ++){
s[i].clear();
for(int j = 0; j < a[i].size() ; j ++){
s[i].insert(a[i][j]);
}
}
if(!ok){
puts("No solution");
}else{
solve();
}
}
return 0;
}
/*
100
7 3
3 1 4 6
3 2 5 7
1 3
*/