文章目录
- 前言
- 题目
- 思路
- 代码
- 后记
前言
可能以前会,但现在不会,但又会了
题目
思路
说白了就是找环后将返祖边颜色染为2
我们可以复习一下有向图DFS树边的类型,树边、返祖边、横叉边、后向边
怎么找环呢,我们并不能简单的vis,因为可能这样:
于是我们需要给每个点3个状态:未访问,正在访问它的子树,已访问。
当然我们可以用栈来维护此时访问的点,但也能用不同标记表示
我们1次DFS可能找不完点,要注意一下需要多次DFS,一定可以把访问到的环至少一条边找完
代码
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
int read(){
bool f=0;int x=0;char c=getchar();while(c<'0'||'9'<c){
if(c=='-')f=1;c=getchar();}while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();return !f?x:-x;
}
#define MAXN 100000
#define INF 0x3f3f3f3f
struct Edge{
int v,id,nxt;
}edge[2*MAXN+5];
int ecnt,head[MAXN+5];
inline void Addedge(int u,int v,int id){
edge[++ecnt]=(Edge){
v,id,head[u]},head[u]=ecnt;return ;
}
bool f;
int col[MAXN+5],vis[MAXN+5];
void DFS(int u){
vis[u]=1;for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v,id=edge[i].id;col[id]=1;if(vis[v]){
if(vis[v]==1)f=1,col[id]=2;continue;}DFS(v);}vis[u]=2;return ;
}
int main(){
int n=read(),m=read();for(int i=1;i<=m;i++){
int u=read(),v=read();Addedge(u,v,i);}for(int i=1;i<=n;i++)if(!vis[i])DFS(i);puts(f?"2":"1");for(int i=1;i<=m;i++)printf("%d",col[i]),putchar(i==m?'\n':' ');return 0;
}
后记
在网上发现了更好的做法,你跑一遍拓扑排序判环,如果没有环全输出1,否则一个环上一定存在 u>vu>vu>v 的边和 u<vu<vu<v 的边,不是环上的边可以不管(1,2颜色都可以)于是直接 u>vu>vu>v 的边颜色为1, u<vu<vu<v 的边颜色为2即可
妙啊!