拓扑排序入门详解&&Educational Codeforces Round 72 (Rated for Div. 2)-----D

https://codeforces.com/contest/1217

D:给定一个有向图,给图染色,使图中的环不只由一种颜色构成,输出每一条边的颜色

不成环的边全部用1染色

ps:最后输出需要注意,一个环上的序号必然是非全递增的,若有环且有一条边u->v,u的序号

 

可以用dfs染色或者用拓扑排序做

 

顺便复习一下拓扑排序:

拓扑排序是将有向无环图的所有顶点排成一个线性序列,使得图中任意两个顶点u,v若存在u->v,那么序列中u一定在v前面。

了解一个概念: DAG-->有向无环图,一个有向图的任意顶点都无法通过一些有向边回到自身,称之为DAG

 

算法过程:

(1)定义一个队列,把所有入度为0的结点加入队列(图有n个点)

(2)取队首节点,输出,删除所有从他出发的边,并令这些边的入度-1,若某个顶点的入度减为0,则将其加入队列

(3)反复进行(2)操作,直到队列为空;

注意:若队列为空时入过队的节点数目恰好为n,说明拓扑排序成功,图为DAG,否则图中有环

 

这位博主写的挺好的 https://blog.csdn.net/qq_41713256/article/details/80805338

拓扑排序入门详解&&Educational Codeforces Round 72 (Rated for Div. 2)-----D_第1张图片

 

 

拓扑排序的博客

https://www.jianshu.com/p/3347f54a3187

dfs版拓扑排序

https://blog.csdn.net/wjh2622075127/article/details/82712940

 

#include

using namespace std;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
/*-------------------------------------------------------------------*/
typedef long long ll;
const int maxn=5010;
int du[maxn];
ll cnt;
int n,m;
int s;
vectorG[maxn];
pairans[maxn];
queueq;
int main()
{	
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
    //一个环上的序号必然是非全递增的 
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		
		int u,v;
		cin>>u>>v;
		
		G[u].push_back(v);
		
		ans[i].first=u;ans[i].second=v;
		
		//入度 
		du[v]++;
	}
	
	for(int i=1;i<=n;i++) if(du[i]==0) q.push(i);
	
	while(!q.empty()){
		
		int now=q.front();q.pop();
		
		int len=G[now].size();
		
		for(int i=0;ians[i].second)
    		cout<<1<<" ";
    		else cout<<2<<" ";
    	}
	}
    else{ //无环直接输出1
    	
    	cout<<1<

DFS版:

dfs过程中有3个状态1,-1,0,1表示当前搜索路径,-1表示已搜索过且无环路径,0表示还未搜索,可以用前向星存边或者vector存边

其他需要注意的代码有注释

ps:讲个大家不容易理解的地方,这个DFS的点是不是可以从任意起点搜索?答案:是的,这个对拓扑序列没有影响,可通过代码自由验证。

有向图DFS过程中(不判环的情况下),我们用栈去存储他的拓扑序列,当一个点没有后驱节点时,这个节点入栈,记住栈的性质(后进先出),然后回溯,这样,越是后面的节点就会被压进栈底

比如说有向边u->v,u是v的前驱,若存在u->v>t,t在拓扑序列中一定在u的后面(拓扑排序的性质),我们从v开始搜索,到t终止(无后驱节点),回溯,入栈,v入栈,回溯。

最后我们搜索u,发现u的后驱节点已标记,所以入栈,退出完成拓扑排序

所以,以DFS回溯+栈的形式就可以很好地完成一次拓扑排序

 

前向星版本:

#include

using namespace std;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
/*-------------------------------------------------------------------*/
typedef long long ll;
const int maxn=5010;
struct node{
	int to,next;
}star[6000];

ll cnt;
int n,m;
int vis[maxn],head[maxn];
void add(int u,int v){
	star[cnt].to=v;
	star[cnt].next=head[u];
	head[u]=cnt++;
}
bool dfs(int idx){
	
	vis[idx]=1;
	for(int i=head[idx];i!=-1;i=star[i].next){
		
		int v=star[i].to;
		if(vis[v]==1)return false;
		//若搜索过程中发现回到本次搜索过的点,说明有环,退出 
		if(vis[v]==0&&!dfs(v))return false;
		
	}
	vis[idx]=-1;//目前路径上不存在环,所以标记为-1 
	return true;
}
pairp[maxn];
int main()
{	
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
    //一个环上的序号必然是非全递增的 
    memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		
		int u,v;
		cin>>u>>v;
		add(u,v);
		p[i].first=u,p[i].second=v;
	}
	int flag=0;
	for(int i=1;i<=n;++i){
		if(!vis[i]){
			if(!dfs(i)){
				flag=1;
				break;
			}
			
		}
	}
	if(flag){
		cout<<2<p[i].second)cout<<2<<" ";
			else cout<<1<<" ";
		}
	}
    else{
    	cout<<1<

vector版本:

#include

using namespace std;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
/*-------------------------------------------------------------------*/
typedef long long ll;
const int maxn=5010;
struct node{
	int to,next;
}star[6000];

vectoredge[maxn]; 


ll cnt;
int n,m;
int vis[maxn],head[maxn];

bool dfs(int idx){
	
	int len=edge[idx].size();
	vis[idx]=1;
	for(int i=0;ip[maxn];
int main()
{	
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
    //一个环上的序号必然是非全递增的 
    memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		
		int u,v;
		cin>>u>>v;
		
		p[i].first=u,p[i].second=v;
		
		edge[u].push_back(v);
		
	}
	int flag=0;
	
	for(int i=1;i<=n;++i){
		
		if(!vis[i]){
			if(!dfs(i)){
				flag=1;
				break;
			}
		}
		
		
	}
	
	
	if(flag){
		cout<<2<p[i].second)cout<<2<<" ";
			else cout<<1<<" ";
		}
	}
    else{
    	cout<<1<

 

你可能感兴趣的:(codeforce,拓扑排序)