如果给定一个DAG和其按字典序拓扑排序的结果,那么对这个DAG所有边取反后一定能够得到一个新的DAG,且这个新的DAG的逆字典序拓扑排序结果就是原来拓扑排序结果的逆序。
因为如果将拓扑排序的结果倒序来看的话,首先拓扑结构肯定是倒着的,其次同级之间的字典序也肯定是倒着的。
所以我是一开始没想清楚,然后反着建图,然后逆字典序序拓扑排序,然后反着输出就过了。
如果你要正常建图,要用dfs求顺字典序拓扑排序的话,那就要保证入度为零的点是先输出的点,枚举儿子时倒序枚举,就好了。
dfs是return前压入栈的,因为必须要保证儿子们全部入栈了后,你才能入栈。
之所以要逆序枚举,是为了让字典序大的先入栈,字典序小的后入栈。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;
int N;
vector<int>G[maxn<<1];
int id[maxn<<1];
char MAP[maxn];
int vis[maxn<<1];
queue<int>s;
bool dfs(int u)
{
vis[u]=-1;
sort(G[u].begin(),G[u].end());
for(int i=0;i<(int)G[u].size();i++)
{
int v=G[u][i];
if(vis[v]<0) return false;
if(!vis[v]&&!dfs(v)) return false;
}
vis[u]=1;
if(id[u]!=N) s.push(u);
return true;
}
void solve()
{
scanf("%d",&N);
while(!s.empty()) s.pop();
for(int i=1;i<=(N<<1);i++)
{
G[i].clear();
id[i]=0;
vis[i]=0;
}
for(int i=1;i<=N;i++)
{
scanf("%s",MAP+1);
for(int j=1;j<=N;j++)
if(MAP[j]=='X')
{
G[i+N].push_back(j);
id[j]++;
}
else
{
G[j].push_back(i+N);
id[i+N]++;
}
}
for(int i=1;i<=(N<<1);i++) if(!id[i]&&!vis[i]) if(!dfs(i)) {puts("No solution");return;}
if(s.empty())
{
puts("No solution");
return;
}
while(!s.empty())
{
int x= s.front();s.pop();
printf("%c%d",x>N?'R':'C',x>N?x-N:x);
if(s.empty()) puts("");
else printf(" ");
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--) solve();
return 0;
}