有向图 & 无向图 环判断
公司成天坑爹考试;不过我下个月才考。闲来无事,写个算法玩玩。
PS,公司坑爹,不让用stl;所以用一个数组来替代stl::stack。
++++++++++++++++++++++++++++++++++++
#无向图
无向图比较简单,只需要用一个辅助的 Visit 数据记录点是否被访问过即可。
#include <iostream> //#include <stack> using namespace std; #define T_LEN 301 int Answer; //0: has no circle; 1: has circle; int N, E; //N: number of point; E: number of edge; int Edge[T_LEN][T_LEN]; int Visit[T_LEN]; //has been visited or not //stack<int> SCircle; int SCircle[T_LEN]; //store the circle int g_index; //key point of circle (position) int g_circle_item; //the key point of circle (value) //trave Graphic from '_index'; //if has circle, return 1; else, return 0 to continue; int TVisit(int _index) { int res = 0; int j; int ind = _index; if (1 == Visit[ind]) { res = 1; } else { Visit[ind] = 1; SCircle[g_index++] = ind; for (j = 1; j <= N; j++) { if (1 == Edge[ind][j]) { Edge[ind][j] = Edge[j][ind] = 0; if (1 == Visit[j]) { res = 1; SCircle[g_index] = j; g_circle_item = j; break; } else { if (TVisit(j) == 1) { res = 1; break; } else { //popup stack SCircle[g_index-1] = 0; g_index--; } } } } } return res; } void TCase(int _index) { int i, j; int a, b; //input & init cin >> N >> E; for (i = 1; i <= N; i++) { Visit[i] = 0; SCircle[i] = 0; for (j = 1; j <= N; j++) { Edge[i][j] = 0; } } for (i = 0; i < E; i++) { cin >> a >> b; Edge[a][b] = Edge[b][a] = 1; } g_index = 0; //processing for (i = 1; i <= N; i++) { if (Visit[i] == 0) { //has not visited; then traverse the graphics from 'i'; Answer = TVisit(i); if (Answer == 1) { //print circle j = g_index - 1; while (SCircle[j] != g_circle_item) j--; for (; j <= g_index; j++) { cout << SCircle[j] << " "; } break; } } } } int main(void) { int i, T; freopen("graphics.txt", "r", stdin); cin >> T; for (i = 0; i < T; i++) { cout << "Case " << i + 1 << "# "; Answer = 0; TCase(i); cout << ( (Answer == 1) ? "has " : "has no " ) << "circle" << endl; } return 0; }
++++++++++++++++++++++++++++++++++++
#有向图
一开始也尝试用DFS的方式(和无向图一样)来判断环,但发现还是有一些差别的。
后来搜了下,才知道每个顶点的状态不对。
图中的一个节点,根据其C[N]的值,有三种状态: 0,此节点没有被访问过 -1,被访问过至少1次,其后代节点正在被访问中 1,其后代节点都被访问过。 按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能: 1、如果C[V]=0,这是一个新的节点,不做处理 2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。 3、如果C[V]=1,类似于2的推导,没有环。
#include <iostream> //#include <stack> using namespace std; #define T_LEN 301 int Answer; //0: has no circle; 1: has circle; int N, E; //N: number of point; E: number of edge; int Edge[T_LEN][T_LEN]; int Visit[T_LEN]; //has been visited //stack<int> SCircle; int SCircle[T_LEN]; int g_index; int g_circle_item; //trave Graphic from '_index'; //if has circle, return 1; else, return 0 to continue; int TVisit(int _index) { int res = 0; int j; int ind = _index; Visit[ind] = -1; SCircle[g_index++] = ind; for (j = 1; j <= N; j++) { if (1 == Edge[ind][j]) { if (Visit[j] == -1) { //find circle res = 1; SCircle[g_index] = j; g_circle_item = j; goto TVisit_END; } else if (Visit[j] == 0) { //has no visited if (TVisit(j) == 1) { res = 1; goto TVisit_END; } else { SCircle[g_index - 1] = 0; g_index--; } } } }//for Visit[ind] = 1; TVisit_END: return res; } void TCase(int _index) { int i, j; int a, b; //input & init cin >> N >> E; for (i = 1; i <= N; i++) { Visit[i] = 0; SCircle[i] = 0; for (j = 1; j <= N; j++) { Edge[i][j] = 0; } } for (i = 0; i < E; i++) { cin >> a >> b; Edge[a][b] = 1; } g_index = 0; //processing for (i = 1; i <= N; i++) { if (Visit[i] == 0) { //has not visited; then traverse the graphics from 'i'; Answer = TVisit(i); if (Answer == 1) { //print circle for (j = 0; j <= g_index;j++) cout << SCircle[j] << " "; break; } } } } int main(void) { int i, T; freopen("graphics_ex.txt", "r", stdin); cin >> T; for (i = 0; i < T; i++) { cout << "Case " << i + 1 << "# "; Answer = 0; TCase(i); cout << ( (Answer == 1) ? "has " : "has no " ) << "circle" << endl; } return 0; }