Codeforces Round #656 (Div. 3) E. Directing Edges(补题)

Codeforces Round #656 (Div. 3) E. Directing Edges(补题)_第1张图片

Codeforces Round #656 (Div. 3) E. Directing Edges(补题)_第2张图片

Codeforces Round #656 (Div. 3) E. Directing Edges(补题)_第3张图片

Codeforces Round #656 (Div. 3) E. Directing Edges(补题)_第4张图片

题意:给一个图,有些是有向的有些是无向的。要求将无向的标成有向的,并且让整个图不形成环。如果可以输出YES并给出其中一种方案。否则输出NO。

做不出来的原因:不会拓扑排序。思考的时候想到过使用并查集但是被一个点连着所有点的有向给否定了。其实有一个拓扑排序的意思,就是知道点的前后顺序就行了。但是还是太菜了。

拓扑排序

拓扑排序的算法是:将有向图的入度为0的点去掉,然后去掉它所连接的边,然后先去的排在前面,后去的排在后面,直到全部去除完毕。形成的排序就叫做拓扑排序。

如果去除到最后发现仍然有点,说明有环,否则应该能去除所有的点。

实现

首先用vector维护图,放入以后用数组记录一下每个点的入度。结束后遍历数组,记录是否有点入度为0,是的话就放入队列。然后从队列出发,每次push一个点出来,并将和这个点相连接的点的入度--,如果相连接的点已经为0了,放入队列即可。直到队列为空。此时若是已经遍历了所有的点,则说明无环,否则有环。

 

本题根据有向完成拓扑排序后,只需要将无向再处理一下。按拓扑排序的顺序从小到大即可(因为这样就不会影响拓扑排序的顺序,从而说明仍然可以按照原来的拓扑排序去走。因为你把边放在了从前到后,回忆拓扑排序过程,增加这条边不会影响之前所有点的入度,因此拓扑排序不变。而当这个点被去除后,新增加的边也被删除了,因此也不影响后面)

代码

#include
using namespace std;
const int N=200005;
int edf[N],edin[N],edout[N];//用来放入无向边
int V;//点数
queue q;//维护一个入度为0的顶点的队列 
vector gra[N];//邻接矩阵 
int in_degree[N];//维护图中每个点的入度
int tp[N];//拓扑排序以后点所对应的顺序 
int tpflag;
void Graph(int V);                   // 构造函数
void addEdge(int v, int w);     // 添加边
bool topological_sort();        // 拓扑排序 

//初始化图 
void Graph()
{	
	//清空图 
	for (int i=0;i

代码有点长,主要有一个拓扑排序的板子占用了60多行。

 

这题还是有点意思的。主要思考问题在拓扑排序。拓扑排序就是一个经典的计算机思维:我并不要求这个结果能完全反应原图,但是它能很好的反应原图的一些信息。各个点之间要么是指向要么无关联。为了不成环怕就怕反过来,那么指向和无关联对我来说无所谓。这样就可以把图给改成一个拓扑排序了。

本小垃圾的易错点:

点是1-V,习惯性0-V-1

点和边日常性弄反,打印边的时候m写成了V,拓扑里面和点比较的时候又变成了和边比较。

你可能感兴趣的:(算法训练)