最近要写题解时才发现自己之前写过,风格囧人,不要介意(。・∀・)ノ゙
Problem
题目概要:
给定一张图,求字典序最靠前的拓扑序,若无则输出Impossible!
Solution
这题是给定一张图,再求字典序最靠前的拓扑序,一开始有一点点思路就是先往①所在分支走,强行取①,再往②走,强行取②,我甚至为我的暴力制定了宏伟的蓝图:
tarjan判环+树状dp求当前点可遍历到的最小点+类似于dijkstra之类的东东
t
a
r
j
a
n
判
环
+
树
状
d
p
求
当
前
点
可
遍
历
到
的
最
小
点
+
类
似
于
d
i
j
k
s
t
r
a
之
类
的
东
东
后来一看,发现若是一个点有俩爹则会挂 (╯°Д°)╯︵ ┻━┻
冷静冷静,发现题目重在优先取小数字,但是会有一些大数字放在小叔子前边儿挡着小数字,看不到啊 (ʘдʘ╬)
那我们就从后边儿看,优先取大数字,从拓扑图(事实证明有可能是假的拓扑图)的后面,也就是叶子结点开始 ,就能巧妙地绕过障碍数字
(o゜▽゜)o☆[BINGO!]
(
o
゜
▽
゜
)
o
☆
[
B
I
N
G
O
!
]
%%%%%再拜ysp大佬%%%%%
所以每次取走叶子结点中最大的,就有可能有结点变成叶子结点
明眼人一看就知道要用堆
每次取最大的叶子加入ans数组,删掉,再把这个叶子的爹爹们儿子数-1,当有爹爹没儿子时,把这个没儿子的爹爹加入堆中,最后逆向输出ans数组
Code
#include<bits/stdc++.h>
using namespace std;
#define cl(x) memset(x,0,sizeof(x))
template <typename _Tp> inline void read(_Tp &x){
char c11=getchar();x=0;bool booo=0;
while(c11<'0'||c11>'9'){if(c11=='-')booo=1;c11=getchar();}
while(c11>='0'&&c11<='9'){x=x*10+c11-'0';c11=getchar();}
if(booo)x=-x;
return ;
}
const int maxn=100050,maxm=100050;
int n,m;
bool bo[maxn];
struct node {int next,v;} a[maxm];
int head[maxn],p=0;
int tot[maxn],s[maxn];
int heap[maxn],top=0;
inline void add(int,int);
void init();
inline void push(int x){ //强烈建议手打堆,好调试,无bug,时间复杂度还小
heap[++top]=x;
int pp=top;
while(pp>1&&heap[pp>>1]<heap[pp]){swap(heap[pp>>1],heap[pp]);pp>>=1;}
return ;
}
inline void pop(){
heap[1]=heap[top--];
int pp=1;
while(((pp<<1)<=top&&heap[pp<<1]>heap[pp])||((pp<<1|1)<=top&&heap[pp<<1|1]>heap[pp])){
pp<<=1;
if(heap[pp]<heap[pp|1])pp|=1;
swap(heap[pp],heap[pp>>1]);
}
return ;
}
void work(){
for(int i=1;i<=n;i++)
if(!tot[i])
push(i);
if(!top){
printf("Impossible!\n");
return ;
}
for(int i=n;i;i--){
if(!top){
printf("Impossible!\n");
return ;
}
int x=heap[1];pop();
s[i]=x;
for(int j=head[x];j;j=a[j].next){
int v=a[j].v;
tot[v]--;
if(!tot[v])push(v);
}
}
for(int i=1;i<=n;i++)printf("%d ",s[i]);
printf("\n");
return ;
}
int main(){
int T;
read(T);
while(T--){
init();
work();
}
return 0;
}
void init(){
top=0;p=0;
cl(bo);cl(head);cl(tot);
read(n);read(m);
int A,B;
for(int i=1;i<=m;i++){
read(A);read(B);
add(B,A);
}
}
inline void add(int u,int v){
a[++p].v=v;
a[p].next=head[u];
head[u]=p;
tot[v]++;
return ;
}