E. Directing Edges
题意:给出n个点和m条边
m条边有两种类型
一种是已经确定了方向的边,一种是还未确定方向的边
要求让我们确定所有边的方向后,图无环
思路:我们先按已经确定方向的边建图跑拓扑排序
然后再按跑拓扑排序的顶点的顺序来建未确定方向的边即可
那么怎么确立呢?即:顶点在拓扑排序中小的建向大的,这样建肯定能满足无环
为什么呢?因为我们在把这些不确定方向的边加进去的时候
如果是从小的往大的加,那么在重新跑拓扑排序的时候,小的肯定是先跑到的,然后他就能消除了这一条边的入度
然后大的边到最后也能跑到
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); using namespace std; const int maxn=2e5+10; struct node { int op,u,v; }a[maxn]; struct hah { int v,nxt; }G[maxn]; int head[maxn]; int num; int du[maxn];int n,m; int ans[maxn]; void add(int u,int v) { G[++num].v=v;G[num].nxt=head[u];head[u]=num; } int tuopu() { queue<int>q; // printf("n;%d m:%d\n",n,m); for(int i=1;i<=n;i++){ if(!du[i]) q.push(i); } int cot=0; while(!q.empty()){ int u=q.front(); // printf("u:%d\n",u); q.pop(); cot++; ans[u]=cot; for(int i=head[u];i;i=G[i].nxt){ int v=G[i].v; du[v]--; if(!du[v]) q.push(v); } } // printf("cot:%d\n",cot); if(cot==n) return 1; else return 0; } void init() { memset(head,0,sizeof(head)); num=0; memset(du,0,sizeof(du)); } int main() { int T; scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&a[i].op,&a[i].u,&a[i].v); if(a[i].op==1){ add(a[i].u,a[i].v); du[a[i].v]++; } } int flag=tuopu(); // printf("flag:%d\n",flag); if(flag==0) printf("NO\n"); else{ printf("YES\n"); for(int i=1;i<=m;i++){ if(a[i].op==1){ printf("%d %d\n",a[i].u,a[i].v); } else{ if(ans[a[i].u]<ans[a[i].v]){ printf("%d %d\n",a[i].u,a[i].v); } else printf("%d %d\n",a[i].v,a[i].u); } } } } return 0; }