ACM学习-单行道问题

来源:互联网 发布:亚马逊和淘宝哪个大 编辑:程序博客网 时间:2024/04/26 17:58
// ACM学习-单行道问题.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include<iostream>
using namespace std;


const int max_node = 201;//可处理最大节点数
char a[max_node][max_node];//邻接矩阵
int f[max_node], rank1[max_node], father[max_node];
int g[max_node];


int n, m, pre_counter, post_counter;


void read_data(){
int x, y, z;
scanf_s("%d%d",&n,&m);
memset(a,0,sizeof(a));
while (m--){
scanf_s("%d%d%d",&x,&y,&z);
if (z == 2){//如果是双向边
a[x][y] = a[y][x] = 2;
}
else{//如果是单向边
a[x][y] = 1;
a[y][x] = -1;
}
}
}
//从指定节点出发,深度遍历有向图,找出割边
void find_bridge(int u){
int v;
rank1[u] = f[u];
for (v = 1; v <= n; v++){
if (!a[u][v])continue;
if (f[v])//已经被访问过
{
if (v != father[u]){
if (f[v] < rank1[u])
rank1[u] = f[v];
}
}
else{//没有被访问过
father[v] = u;
f[v] = f[u] + 1;//v的前序编号等于父亲的加1
find_bridge(v);
if (rank1[v]>f[u])
{
cout << u << ":" << v << endl;
a[u][v] = a[v][u] = 0;
}
else if (rank1[v] < rank1[u])
rank1[u] = rank1[v];
}

}


}
//1--访问过:如果后面的点的周围的点的深度比他的父亲深度还浅(小)保留u->v
//2--没有访问过:1.儿子的深度比父亲的浅,保留u->v  2.儿子的深度比父亲的深,保留v->u
void dfs(int u){
int v;
f[u] = pre_counter++;//令前序标号等于前序计数器的值
rank1[u] = f[u];
for (v = 1; v <= n; v++){
if (a[u][v] <= 0)continue;
if (f[v]){
if (f[v] < f[u] && v != father[u]){
//1 一个已经访问完的群(v),只有u->v这条单向边
//2 v是除了u的父亲外的祖先
if (a[u][v] == 2) cout << u << ":" << v << endl;
if (g[v])rank1[u] = 1;
else if (f[v] < rank1[u])rank1[u] = f[v];
}
}
else{
father[v] = u;
dfs(v);
if (rank1[v] <= f[u]){//跳跃边,v有通向深度比u小的边
if (a[u][v] == 2){//双向边
a[v][u] = 0;
cout << u << ":" << v << endl;
}
if (rank1[v] < rank1[u])rank1[u] = rank1[v];
}
else{
cout << v << ":" << u << endl;
}


}
}
g[u] = post_counter++;


}




int _tmain(int argc, _TCHAR* argv[])
{
int i;
read_data();
memset(f,0,sizeof(f));
f[1] = 1;
find_bridge(1);//找出所有的割边
memset(g,0,sizeof(g));
memset(f, 0, sizeof(f));
for (i = 1; i <= n; i++){
if (!f[i]){
pre_counter = post_counter = 1;
dfs(i);
}
}
return 0;
}

0 0
原创粉丝点击