CF2000分图论
题意:给你一个n个顶点m条边的图,其中一些边没有方向,其余边有方向,让你对每一条没有方向的边赋一个方向,要求最终图不能形成自环。(没有重边)
题解:首先先看有方向的边所构成的图原本是否已经成环,如果成环的话必定直接输出NO,不成环的话则必定输出YES。统计每个点的indeg,进行拓扑排序,按照拓扑序的dfn顺序,把无向边的u和v两个点连线方向从拓扑序小的指向拓扑序大的。这样必定不会成环(这是拓扑排序的性质之一)
AC代码:
#include<bits/stdc++.h> #pragma GCC optimize(2) #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=2e5+5; int tot,head[maxn]; struct E{ int to,next; }edge[maxn<<1]; void add(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } int n,m,indeg[maxn],dfn[maxn]; bool topsort(){ queue<int> q;int ct=0; rep(i,1,n) if(!indeg[i]) q.push(i); while(!q.empty()){ int now=q.front();q.pop(); dfn[now]=++ct; for(int i=head[now];i!=-1;i=edge[i].next){ int v=edge[i].to; if(--indeg[v]==0) q.push(v); } } if(ct!=n) return false; else return true; } int main(){ int T;scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); mem(indeg,0),mem(head,-1),tot=0; vector<pair<int,int> >vec; vector<pair<int,int> >lol; rep(i,1,m){ int op,u,v;scanf("%d%d%d",&op,&u,&v); if(!op){ vec.pb({u,v}); }else{ add(u,v);indeg[v]++; lol.pb({u,v}); } } if(!topsort()){puts("NO");continue;} else{ puts("YES"); for(auto it:vec){ int a=it.first,b=it.second; if(dfn[a]>dfn[b]) swap(a,b); printf("%d %d\n",a,b); } } for(auto it:lol){ printf("%d %d\n",it.first,it.second); } } }View Code