BDFZOI 边的分类
涉及知识:基础图论/DFS
提交次数:4
描述
给定无权有向图G(V,E),dfs确定每条边的种类。当边(u, v)第一次被遍历,
考虑v的颜色
1.白色,(u,v)为T边,包含在dfs树中
2.灰色,(u,v)为B边,dfs树中子孙指向自己直系祖先的一条边
3.黑色: (u,v)为F边或C边. 此时需要进一步判断
3.1. 若prev[u]<prev[v]:u是v的直系祖先,F边<prev[v]:u是v的直系祖先,f边
3.2. 若prev[u]>prev[v]:v早就被发现了, C边
输入
第一行包含两个整数N、M,表示该图共有N个结点和M条有向边。(N <= 5000,M <= 200000)
接下来M行,每行包含2个整数{u,v},表示有一条有向边 u指向v
输出
M行,依照输入顺序,每行输出边的u、v、种类
样例输入
5 9 1 2 1 3 1 4 2 3 3 4 3 5 5 1 5 2 5 4
样例输出
1 2 T 1 3 F 1 4 F 2 3 T 3 4 T 3 5 T 5 1 B 5 2 B 5 4 C
代码:
1 #include<iostream>
2 #include<vector>
3 #include<cstring>
4 #include<cstdio>
5 using namespace std;
6 int n, m;
7 struct edge{
8 int u, e;
9 };
10 vector<vector<edge> >v(5005);
11 int dfn[5005];
12 int finish[5005];
13 bool visited[5005];
14 int ttime;
15
16 void dfs(int uu, int step){
17 dfn[uu] = ttime++;
18 for(int i = 0; i < v[uu].size(); i++){
19 int next = v[uu][i].u;
20 if(dfn[next]==-1) v[uu][i].e = 1;//T边
21 else if (finish[next]==-1) v[uu][i].e = 2;//B边
22 else{
23 if(dfn[next]>dfn[uu]) v[uu][i].e = 3; //F边
24 else if (dfn[next]<dfn[uu]) v[uu][i].e = 4;//C边
25 }
26 if(visited[next]==false){
27 visited[next] = true;
28 dfs(next, step+1);
29 }
30 }
31 finish[uu] = ttime++;
32 }
33 int main(){
34 cin>>n>>m;
35 int i, j;
36 for(i = 1; i <= m; i++){
37 edge ee;
38 int a, b;
39 cin>>a>>b;
40 ee.u = b;
41 ee.e = 0;
42 v[a].push_back(ee);
43 }
44 memset(dfn,-1,sizeof(dfn));
45 memset(finish,-1,sizeof(finish));
46 visited[1] = true;
47 dfs(1,0);
48 for(i = 1; i <= n; i++){
49 if(!visited[i]){
50 visited[i] = true;
51 dfs(i,0);
52 }
53 }
54 for(i = 1; i <= n; i++)
55 for(j = 0; j < v[i].size();j++){
56 switch(v[i][j].e){
57 case 1:
58 cout<<i<<" "<<v[i][j].u<<" "<<"T"<<endl;
59 break;
60 case 2:
61 cout<<i<<" "<<v[i][j].u<<" "<<"B"<<endl;
62 break;
63 case 3:
64 cout<<i<<" "<<v[i][j].u<<" "<<"F"<<endl;
65 break;
66 case 4:
67 cout<<i<<" "<<v[i][j].u<<" "<<"C"<<endl;
68 break;
69 }
70 }
71
72 return 0;
73 }
备注:
这周上课时老师补充的内容,属于比较基础的内容。利用dfs树,设置两个时间戳dfn[i]为发现结点i的时间,finish[i]为离开这个点,
也就是出栈的时间戳。这样就可以将点染色,白色为未访问的结点,即dfn为-1;灰色为已发现,但未完成的结点;黑色则为已完成的结点,
即finish!=-1。于是也可以把边进行分类了,分为树边,前向边,后向边和叉边。具体见dfs内的几行代码。
T树边:灰->白
B后向边:灰->灰
F前向边:灰->黑
C叉边:灰->黑
无向图没有后两者。
还是犯了一些错误的。比如每个点都只能访问一次,对于已经访问过的点,只要判断一下边,不能接着dfs下去。
还有就是图不一定连通,所以每个点都要判断一下要不要dfs。另外得4分是因为忘了标记再次dfs的点。