传送门啦

这个题没有想象中复杂。

我们先有向边建立,因为我们无法改变有向边的方向。

建立完之后跑一边拓扑排序,我们按拓扑序小的指向大的就好了。

解释:

我们知道如果一个点在另一个点顺序的后面的话,如果我们添加这个点回去的边显然是不合理的,所以我们每读入一条无向边的时候我们判断这个点在拓扑排序里面位置的大小,如果 $ u > v $ 就代表 $ u $ 到$ v $ 可能有路线,但是 $ v $ 绝对不能返回 $ u $ ,那么此时如果有一条边要你选择,建立 $ u $ 到 $ v $ 不会使 $ v $ 回到 $ u $ ,判断条件也就非常明显了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 100005; inline int read(){
char ch = getchar();
int f = 1, x = 0;
while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
return x * f;
} int n,p1,p2,u,v;
struct Edge{
int from,to,next;
}edge[maxn << 1];
int head[maxn],tot;
int in[maxn],t[maxn],cnt; void add(int u,int v){
edge[++tot].from = u;
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot;
} void tuopu(){
queue<int> q;
for(int i=1;i<=n;i++)
if(!in[i]) q.push(i);
while(!q.empty()){
int cur = q.front();
t[cur] = ++cnt;
q.pop();
for(int i=head[cur];i;i=edge[i].next){
int v = edge[i].to;
in[v]--;
if(in[v] == 0)
q.push(v);
}
}
} int main(){
n = read(); p1 = read(); p2 = read();
for(int i=1;i<=p1;i++){
u = read(); v = read();
add(u , v);
in[v]++;
}
tuopu();
for(int i=1;i<=p2;i++){
u = read(); v = read();
if(t[u] < t[v]) printf("%d %d\n",u,v);
else printf("%d %d\n",v,u);
}
return 0;
}
05-11 15:49