题目大意自行参考
题解:
首先一个基本的思路是从小到大查看i,然后把制作i需要提前制作的j按照字典序从小到大拓扑排序,然后这相当于是在反图上做字典序最大的拓扑排序。
我就是这么做的,字典序拓扑排序可以用一个堆维护,就是有多个选择的时候选择字典序最值是最优的。
看到好像其实就是反图的最大字典序拓扑排序?QwQ
代码:
//BZOJ 4010
//HNOI 2015
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#define MAXN 100010
using namespace std;
vector<int> g[MAXN];
int tlist[MAXN],ans[MAXN];
int d[MAXN],vis[MAXN],tcnt;
priority_queue<int> q;
stack<int> s;queue<int> bq;
int bfs(int s)
{
while(!bq.empty()) bq.pop();
bq.push(s);vis[s]=true;
while(!bq.empty())
{
int x=bq.front();bq.pop();
for(int i=g[x].size()-1;i>=0;i--)
{
if(!vis[g[x][i]])
{
bq.push(g[x][i]);
vis[g[x][i]]=s;
}
if(vis[g[x][i]]==s) d[g[x][i]]++;
}
}
return 0;
}
int toposort(int s)
{
while(!q.empty()) q.pop();q.push(s);
while(!q.empty())
{
int x=q.top();q.pop();tlist[++tcnt]=x;
for(int i=g[x].size()-1;i>=0;i--)
if(vis[g[x][i]]==s)
{
d[g[x][i]]--;
if(!d[g[x][i]]) q.push(g[x][i]);
}
}
return 0;
}
int main()
{
int tests;scanf("%d",&tests);
while(tests--)
{
int n,m;scanf("%d%d",&n,&m);
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++) g[i].clear();
memset(vis,false,sizeof(vis));
while(!s.empty()) s.pop();
while(m--)
{
int u,v;scanf("%d%d",&u,&v);
g[v].push_back(u);d[u]++;
}
for(int i=1;i<=n;i++)
if(!d[i]) s.push(i);
int cnt=0;
while(!s.empty())
{
int x=s.top();s.pop();cnt++;
for(int i=g[x].size()-1;i>=0;i--)
{
d[g[x][i]]--;
if(!d[g[x][i]]) s.push(g[x][i]);
}
}
if(cnt<n)
{
printf("Impossible!\n");
continue;
}
cnt=0;
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
if(!vis[i])
{
bfs(i);tcnt=0;toposort(i);
for(int j=1;j<=tcnt;j++)
ans[++cnt]=tlist[tcnt-j+1];
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}