본문 바로가기

미연시리뷰

(알고리즘 설계와 분석)배열에 기반한 그래프의 dfs

<헤더파일>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NONE -1

typedef struct _edge {
int  name;
int  vf, vr;  // e = (vf, vr) where vf, vr are vertex array indices
int  cost;    // edge cost
bool flag;    // true if in an SP, false otherwise 
int  fp, rp;  // adj list ptr of forward and reverse (-1 if none)
} edge;

typedef struct _vertex {
int  name;
bool flag;
int  f_hd, r_hd; // adj list header(-1 if none)
} vertex;

 

<<메인 함수>>


#include "Graph_adj_array.h"
#include <queue>

int Tree_Check_adj_array(int Vnum, vertex V[], int Enum, edge E[]);
void Read_Graph_adj_array(int Vnum, vertex V[], int Enum, edge E[]);
int DFS_Tree_adj_array(int src, int Vnum, vertex *V, int Enum, edge *E);

unsigned long usedMemoryForArray;
void errorExit(const char *s);

int main ( void ) {
int    Vnum, Enum, src;
vertex *V;
edge   *E;
int    Tnum; // # of test cases
int    Tree_cost; // DFS_tree cost
int    Memsize_for_array;
clock_t start, finish;
double cmpt;

scanf_s("%d", &Tnum);

for (int t = 0; t < Tnum; t++ ) {
scanf_s("%d %d %d", &Vnum, &Enum, &src);
V = new vertex [Vnum];
E = new edge [Enum];
if ( V == NULL || E == NULL ) {
errorExit("Memory Allocation Error");
}
Memsize_for_array = Vnum * sizeof(vertex) + Enum * sizeof(edge);
if (usedMemoryForArray < (unsigned long)Memsize_for_array ) {
usedMemoryForArray = Memsize_for_array;
}
Read_Graph_adj_array(Vnum, V, Enum, E);
// Do DFS
start = clock();

//     for ( int i = 0; i < Vnum; i++ ) {
//   V[i].flag = false;  // clear flag
//     }
//     for ( int i = 0; i < Enum; i++ ) {
//   E[i].flag = false;  // clear flag
//     }
Tree_cost = DFS_Tree_adj_array (src, Vnum, V, Enum, E);

finish = clock();
cmpt = ((double)(finish - start)) / (double)CLK_TCK;

        if (Tree_Check_adj_array(Vnum, V, Enum, E) == 0) { // check if spanning tree
if (t != 0) printf("\n");
printf("**T%d (DFS) (V = %d, E = %d, time = %.3f sec) ERROR: NOT A TREE!!", 
t+1, Vnum, Enum, cmpt);
}
else {
if ( t != 0 ) printf("\n");
printf("**T%d (DFS) (V = %d, E = %d, time = %.3f sec) Tree Cost = %d", 
t+1, Vnum, Enum, cmpt, Tree_cost);
}
delete V; delete E;
}
printf("\nTotal memory used = %d", usedMemoryForArray);
return 0;
}

void errorExit(const char *s) {
printf("%s\n", s);
exit(-1);
}

 

<<DFS 체크 함수>>

#include "Graph_adj_array.h"
//#include "Graph_adj_array_extern.h"
//#include "Graph_adj_array_function.h"
#include <queue>

#define PARENT_OF_ROOT  -100

int Tree_Check_adj_array(int Vnum, vertex V[], int Enum, edge E[]) {
int u = 0, ep, w;
int *visited;
std::queue<int> q;
for ( int i = 0; i < Enum; i++ ) {
if ( E[i].flag == true ) {
++u;
}
}
if ( u != (Vnum-1) ) {
return 0; // it is not a spanning tree
}
visited = new int[Vnum];  // allocate parent array
for (int i=0; i < Vnum; i++ )
visited[i] = NONE;
u = 0;
visited[u] = PARENT_OF_ROOT;
  do {
// check adjacent list at v0 and set Costi_Ni
for ( ep = V[u].f_hd; ep != NONE; ep = E[ep].fp ) { // forward
if ( E[ep].flag == false ) {
continue;
}
w = E[ep].vr;
if ( visited[w] == NONE ) {
visited[w] = u;
q.push(w);
}
else if ( visited[u] != w ) { // w is visited and w is not the parent of v,
  // implies that G has a cycle
while ( !q.empty() ) {
q.pop();
}
delete [] visited; 
return 0;
}
}
for ( ep = V[u].r_hd; ep != NONE; ep = E[ep].rp ) { // backward
if ( E[ep].flag == false ) {
continue;
}
w = E[ep].vf;
if ( visited[w] == NONE ) {
visited[w] = u;
q.push(w);
}
else if ( visited[u] != w ) { // w is visited and w is not the parent of v,
  // implies that G has a cycle
while ( !q.empty() ) {
q.pop();
}
delete [] visited; 
return 0;
}
}
if ( q.empty() ) {
for (int i=0; i < Vnum; i++ )
if (visited[i] == NONE) {
delete [] visited; 
return 0; // the graph is not connected
}
delete [] visited; 
return 1;
}
u = q.front();
q.pop();
} while ( 1 );
}

 

<<그래프 생성 및 DFS 시행 함수>>


#include "Graph_adj_array.h"
int arr[100];

void Read_Graph_adj_array (int Vnum, vertex V[], int Enum, edge E[]) {
// read graph information
// V와 E의 name field는 각각 자신의 인덱스를 저장한다
// V[].flag과 E[].flag은 반드시 false로 설정해야 한다.

for (int i = 0; i < Vnum; i++) {
vertex v;
v.name = i;
v.flag = false;
v.f_hd = -1;  v.r_hd = -1;
V[i] = v;
}

int src = 0; int dest = 0; int cost = 0;
int next = -2;
for (int idx = 0; idx < Enum; idx++) {
scanf_s("%d", &src);
scanf_s("%d", &dest);
scanf_s("%d", &cost);

E[idx].vf = src; E[idx].vr = dest; E[idx].cost = 1;
E[idx].flag = false;  E[idx].name = idx;
E[idx].fp = -1; E[idx].rp = -1;

E[idx].fp = V[src].f_hd;
V[src].f_hd = idx;

E[idx].rp = V[dest].r_hd;
V[dest].r_hd = idx;
}
// for (int i = 0; i < Vnum; i++)
// printf("%d %d\n", V[i].f_hd, V[i].r_hd);
// for (int i = 0; i < Enum; i++) {
// printf("%d %d %d %d\n", E[i].fp, E[i].vf, E[i].vr, E[i].rp);
// }
}

int dfs1(int ret, int eg, int Vnum, vertex* V,
int Enum, edge* E, int first);
int dfs2(int ret, int eg, int Vnum, vertex* V,
int Enum, edge* E, int second);

//인자: 정점의 fhd
int dfs1(int ret, int eg, int Vnum, vertex* V,
int Enum, edge* E, int first) {
//해당 에지가 -1이면, 패스
//또는 이미 방문한 거라면 패스
if (eg == -1) {
// ret--;
// printf("-1 exit %d decreased\n", ret);
return ret;
}
if (E[eg].flag == true) {
// printf("ture exit\n");
// ret--;
return ret;
}

while (eg != -1) {
//만일 이번에 해당 간선의 왼쪽의 정점을 방문한 것이라면
if (V[E[eg].vf].flag != true) {
V[E[eg].vf].flag = true;
E[eg].flag = true;
ret++;

// printf("result is %d now\n", ret);
// printf("Used %d edge\n", E[eg]);
// printf("visited %d\n", V[E[eg].vf].name);
arr[V[E[eg].vf].name] = 0;
//다음은 그 정점의 왼쪽과 오른쪽을 방문해
ret = dfs1(ret, V[E[eg].vf].f_hd, Vnum, V, Enum, E, first);
ret = dfs2(ret, V[E[eg].vf].r_hd, Vnum, V, Enum, E, first);
}
//해당 간선의 오른쪽의 정점을 방문한 것이라면
else if (V[E[eg].vr].flag != true) {
V[E[eg].vr].flag = true;
E[eg].flag = true;
ret++;

// printf("result is %d now\n", ret);
// printf("Used %d edge\n", E[eg]);
// printf("I visited %d\n", V[E[eg].vr].name);
arr[V[E[eg].vr].name] = 0;
// printf("edge %d %d\n", V[E[eg].vr].f_hd, V[E[eg].vr].r_hd);
ret = dfs1(ret, V[E[eg].vr].f_hd, Vnum, V, Enum, E, first);

ret = dfs2(ret, V[E[eg].vr].r_hd, Vnum, V, Enum, E, first);
}
//해당 간선의 모두를 방문했다면
else {
// if (eg == first)
// break;
// printf("%d edge can't visit any vertex\nand return %d\n", E[eg], ret);
// printf("now edge %d\n", eg);
eg = E[eg].fp;
// printf("now edge %d\n", eg);
// return ret;
continue;
}
//이번 간선에 연결된 fp rp를 찾아나설 차례
eg = E[eg].fp;
}

// printf("return %d\n", ret);
return ret;
}

//인자: 정점의 rhd
int dfs2(int ret, int eg, int Vnum, vertex* V,
int Enum, edge* E, int second) {
//해당 에지가 -1이면, 패스
//또는 이미 방문한 거라면 패스
if (eg == -1) {
// ret--;
// printf("-1 exit %d decreased\n", ret);
return ret;
}
if (E[eg].flag == true) {
// printf("ture exit\n");
// ret--;
return ret;
}

while (eg != -1) {
//만일 이번에 해당 간선의 왼쪽의 정점을 방문한 것이라면
if (V[E[eg].vf].flag != true) {
V[E[eg].vf].flag = true;
E[eg].flag = true;
ret++;

// printf("result is %d now\n", ret);
// printf("Used %d edge\n", E[eg]);
// printf("visited %d\n", V[E[eg].vf].name);
arr[V[E[eg].vf].name] = 0;
//다음은 그 정점의 왼쪽과 오른쪽을 방문해
ret = dfs1(ret, V[E[eg].vf].f_hd, Vnum, V, Enum, E, second);
ret = dfs2(ret, V[E[eg].vf].r_hd, Vnum, V, Enum, E, second);
}
//해당 간선의 오른쪽의 정점을 방문한 것이라면
else if (V[E[eg].vr].flag != true) {
V[E[eg].vr].flag = true;
E[eg].flag = true;
ret++;

// printf("result is %d now\n", ret);
// printf("Used %d edge\n", E[eg]);
// printf("I visited %d\n", V[E[eg].vr].name);
arr[V[E[eg].vr].name] = 0;
ret = dfs1(ret, V[E[eg].vr].f_hd, Vnum, V, Enum, E, second);
ret = dfs2(ret, V[E[eg].vr].r_hd, Vnum, V, Enum, E, second);
}
//해당 간선의 모두를 방문했다면
else {
eg = E[eg].fp;
continue;
}

//이번 간선에 연결된 fp rp를 찾아나설 차례
eg = E[eg].rp;
}
// printf("return %d\n", ret);
return ret;
}

int DFS_Tree_adj_array(
int     src,   // source node index
int     Vnum,  // number of vertices
vertex *V,     // vertex structure array (starting index 0)
int     Enum,  // number of edges
edge   *E     // edge structure array (starting index 0) 
) {  
// DFS를 사용하여 DFS tree에 속하는 에지의 flag을 true로 설정한다.
// DFS 시작 vertex는 입력 파일에서 지정된다(src).
// DFS tree에 속한 에지의 cost 함을 return 한다(모든 각 edge cost가 1이면 unique)
// recursive 함수로 작성해도 무방하다.

int ret = 0;  int ret2 = 0;
int* pt = &ret; int* st = &ret2;
int left = V[src].f_hd; int right = V[src].r_hd;
V[src].flag = true;

int first = left;  //the first used edge
int second = right;

ret += dfs1(*pt, left, Vnum, V, Enum, E, first);
*st = ret2;
ret2 += dfs2(*st, right, Vnum, V, Enum, E, second);
ret = ret + ret2;
arr[src] = 0;

return ret;
}

'미연시리뷰' 카테고리의 다른 글

최근접 점의 쌍 찾기  (2) 2020.11.01
(알고리즘 설계와 분석)리스트에 기반한 그래프의 bfs  (0) 2020.10.08
os 0-2 1번 임시 swap  (2) 2020.10.02
이미지 그레이스케일로 변환  (2) 2020.09.15
growable array  (3) 2020.08.09