小白書上經典DFS題目。html
1. 遞歸實現node
// from: https://www.cnblogs.com/huaszjh/p/4686092.html #include <stdio.h> #include <string.h> #define maxn 105 unsigned char data[maxn][maxn]; int m, n, vis[maxn][maxn]; void dfs(int x, int y, int ans) { if (x < 0 || x >= m || y < 0 || y >= n) return; //出界 if (vis[x][y] > 0 || data[x][y] == '*') return; //非'@'或已經訪問 vis[x][y] = ans; //連通份量編號 for (int k = -1; k <= 1; k++) { for (int t = -1; t <= 1; t++) { if (k != 0 || t != 0) { //自身格子不須要重複判斷 dfs(x + k, y + t, ans); } } } } #define DEBUG int main() { #ifdef DEBUG const char* input_txt_pth = "F:/zhangzhuo/debug/OJ/UVA-572.txt"; freopen(input_txt_pth, "r", stdin); #endif int i, j; while (scanf("%d %d", &m, &n) && m &&n) { int count = 0; //連通塊 memset(vis, 0, sizeof(vis)); for (i = 0; i < m; i++) { scanf("%s", data[i]); } for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { //對未訪問且爲`@`的格子進行訪問 if (vis[i][j] == 0 && data[i][j] == '@') { dfs(i, j, ++count); } } } printf("%d\n", count); #ifdef DEBUG for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { printf("%3d", vis[i][j]); } printf("\n"); } printf("\n"); #endif } return 0; }
2. 遞歸dfs函數用迭代實現
每一個節點的dfs遞歸調用,改爲用stack容器就地計算,是個while循環,本質上仍是棧,可是避免了遞歸時嵌套產生的開銷形成的潛在風險。ios
C++的stack、vector容器用起來比較順手。另外就是把座標簡單封裝爲一個結構體。函數
#include <stdio.h> #include <string.h> #include <iostream> #include <stack> #include <vector> typedef struct Coord { char x, y; } Coord; #define DEBUG int main() { #ifdef DEBUG const char* input_txt_pth = "F:/zhangzhuo/debug/OJ/UVA-572.txt"; freopen(input_txt_pth, "r", stdin); #endif int m, n, i, j; #define maxn 105 unsigned char data[maxn][maxn]; int vis[maxn][maxn]; while (scanf("%d %d", &m, &n) && m &&n) { int count = 0; //連通塊 memset(vis, 0, sizeof(vis)); for (i = 0; i < m; i++) { scanf("%s", data[i]); } std::stack<Coord> stk; Coord cd; std::vector<Coord>offset; cd.x = -1; cd.y = -1; offset.push_back(cd); cd.x = -1; cd.y = 0; offset.push_back(cd); cd.x = -1; cd.y = 1; offset.push_back(cd); cd.x = 0; cd.y = -1; offset.push_back(cd); cd.x = 0; cd.y = 1; offset.push_back(cd); cd.x = 1; cd.y = -1; offset.push_back(cd); cd.x = 1; cd.y = 0; offset.push_back(cd); cd.x = 1; cd.y = 1; offset.push_back(cd); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { cd.x = i; cd.y = j; if (vis[cd.x][cd.y] > 0 || data[cd.x][cd.y] != '@') continue; count++; stk.push(cd); while (!stk.empty()) { cd = stk.top(); stk.pop(); vis[cd.x][cd.y] = count; Coord tmp; for (size_t k = 0; k < offset.size(); k++) { tmp.x = cd.x + offset[k].x; tmp.y = cd.y + offset[k].y; if (tmp.x < 0 || tmp.x >= m || tmp.y < 0 || tmp.y >= n) continue; if (vis[tmp.x][tmp.y] > 0 || data[tmp.x][tmp.y] != '@') continue; stk.push(tmp); } } } } printf("%d\n", count); #ifdef DEBUG for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { printf("%3d", vis[i][j]); } printf("\n"); } printf("\n"); #endif } return 0; }
3.純C,DFS非遞歸,自定義棧ADT,函數指針debug
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <string.h> typedef struct Coord Coord; struct Coord { char x, y; }; typedef struct CoordOffset CoordOffset; struct CoordOffset { size_t num; int* x; int* y; }; typedef struct ListNode ListNode; struct ListNode { ListNode* next; void* data; }; typedef struct Stack Stack; struct Stack { ListNode* head; size_t len; void(*push_coord)(Stack* stk, Coord* coord); void (*pop_coord)(Stack* stk); void (*top_coord)(Stack* stk, Coord* coord); }; void stack_push_coord(Stack* stk, Coord* coord) { ListNode* new_head = (ListNode*)malloc(sizeof(ListNode)); /* new_head->data = coord; */ new_head->data = (Coord*)malloc(sizeof(ListNode)); memcpy(new_head->data, coord, sizeof(Coord)); new_head->next = stk->head; stk->head = new_head; stk->len++; } void stack_pop_coord(Stack* stk) { if (stk->head != NULL) { ListNode* new_head = stk->head->next; free(stk->head->data); free(stk->head); stk->head = new_head; stk->len--; } } void stack_top_coord(Stack* stk, Coord* coord) { if (stk->head != NULL) { Coord* t_coord = (Coord*)(stk->head->data); coord->x = t_coord->x; coord->y = t_coord->y; } } void make_stack(Stack** _stk) { Stack* stk = (Stack*)malloc(sizeof(Stack)); stk->head = NULL; stk->len = 0; stk->push_coord = stack_push_coord; stk->pop_coord = stack_pop_coord; stk->top_coord = stack_top_coord; /* write back */ *_stk = stk; } void free_stack(Stack* stk) { ListNode* cur = stk->head; ListNode* temp; size_t i; for (i = 0; i < stk->len; i++) { temp = cur->next; free(cur->data); free(cur); cur = temp; } free(stk); stk = NULL; } void make_8coord_offset(CoordOffset** _offset) { CoordOffset* offset = (CoordOffset*)malloc(sizeof(CoordOffset)); offset->num = 8; offset->x = (int*)malloc(sizeof(int)*offset->num); offset->y = (int*)malloc(sizeof(int)*offset->num); offset->x[0] = -1; offset->y[0] = -1; offset->x[1] = -1; offset->y[1] = 0; offset->x[2] = -1; offset->y[2] = 1; offset->x[3] = 0; offset->y[3] = -1; offset->x[4] = 0; offset->y[4] = 1; offset->x[5] = 1; offset->y[5] = -1; offset->x[6] = 1; offset->y[6] = 0; offset->x[7] = 1; offset->y[7] = 1; /* write back */ *_offset = offset; } void free_coord_offset(CoordOffset* offset) { if (offset) { if (offset->x) { free(offset->x); offset->x = NULL; } if (offset->y) { free(offset->y); offset->y = NULL; } free(offset); offset = NULL; } } /* #define DEBUG */ int main() { #ifdef DEBUG const char* input_txt_pth = "F:/zhangzhuo/debug/OJ/UVA-572.txt"; freopen(input_txt_pth, "r", stdin); #endif int m, n, i, j; size_t k; #define maxn 105 unsigned char data[maxn][maxn]; int vis[maxn][maxn]; /* here we use 8 neighbours */ CoordOffset* offset = NULL; make_8coord_offset(&offset); while (scanf("%d %d", &m, &n) && m &&n) { int count = 0; /* 連通塊 */ memset(vis, 0, sizeof(vis)); for (i = 0; i < m; i++) { scanf("%s", data[i]); } /* std::stack<Coord> stk; */ Stack* stk; make_stack(&stk); Coord cd; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { cd.x = i; cd.y = j; if (vis[cd.x][cd.y] > 0 || data[cd.x][cd.y] != '@') continue; count++; /* stk.push(cd); */ stack_push_coord(stk, &cd); /* while (!stk.empty()) { */ while(stk->len!=0) { /* cd = stk.top(); */ /* stack_top_coord(stk, &cd); */ stk->top_coord(stk, &cd); /* stk.pop(); */ /* stack_pop_coord(stk); */ stk->pop_coord(stk); vis[cd.x][cd.y] = count; Coord tmp; for (k = 0; k < offset->num; k++) { tmp.x = cd.x + offset->x[k]; tmp.y = cd.y + offset->y[k]; if (tmp.x < 0 || tmp.x >= m || tmp.y < 0 || tmp.y >= n) continue; if (vis[tmp.x][tmp.y] > 0 || data[tmp.x][tmp.y] != '@') continue; /* stk.push(tmp); */ /* stack_push_coord(stk, &tmp); */ stk->push_coord(stk, &tmp); } } } } free_stack(stk); printf("%d\n", count); #ifdef DEBUG for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { printf("%3d", vis[i][j]); } printf("\n"); } printf("\n"); #endif } free_coord_offset(offset); return 0; }
4.DFS+並查集實現3d
#include <stdio.h> #include <stdio.h> #include <string.h> #include <stdlib.h> int fa[10500]; int m, n, cnt, vis[105][105]; char mp[105][105]; int find(int x) { if (fa[x] == x) return x; fa[x] = find(fa[x]); return fa[x]; } void merge(int x, int y) { int fx = find(x); int fy = find(y); if (fx == fy) return; fa[fx] = fy; } void dfs(int x, int y, int fx, int fy) { if (x < 0 || x >= m || y < 0 || y >= n) return; if (vis[x][y] || mp[x][y] == '*') return; vis[x][y] = 1; /* cout<<"x || y || fx || fy : "<<x<<" || "<<y<<" || "<<fx<<" || "<<fy<<endl; */ if (fx != -1) { merge(x*m + y, fx*m + fy); } int i, j; for (i = -1; i < 2; i++) { for (j = -1; j < 2; j++) { if (!i && !j) continue; dfs(x + i, y + j, x, y); } } } /* #define LOCAL */ int main() { #ifdef LOCAL const char* input_txt = "F:/zhangzhuo/debug/OJ/UVA-572.txt"; freopen(input_txt, "r", stdin); #endif int i, j; while (scanf("%d%d", &m, &n) == 2 && m && n) { cnt = 0; memset(vis, 0, sizeof(vis)); for (i = 0; i < m; i++) { scanf("%s", mp[i]); } for (i = 0; i < 10500; i++) { fa[i] = i; } for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (!vis[i][j] && mp[i][j] == '@') { dfs(i, j, -1, -1); cnt++; } } } printf("%d\n", cnt); #ifdef LOCAL for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { printf("%3d", vis[i][j]); } printf("\n"); } printf("\n"); #endif } return 0; }
5.DFS+並查集+不使用全局變量+簡單封裝爲結構體指針
#include <stdio.h> #include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct FSU_Node { int p; /* parent id */ int rank; int vis; /* group(connected component) id */ } FSU_Node; /* get node's root id @param x: node id @param nodes: all nodes in map */ int fus_find(int x, FSU_Node* nodes) { if (nodes[x].p == x) return x; nodes[x].p = fus_find(nodes[x].p, nodes); return nodes[x].p; } /* merge two node groups @param a: a node from one node group @param b: a node from another node group */ void fus_union(int a, int b, FSU_Node* nodes) { int ra = fus_find(a, nodes); /* ra: root id of a */ int rb = fus_find(b, nodes); /* rb: root id of b */ if (ra == rb) { return; } if (nodes[ra].rank > nodes[rb].rank) { nodes[rb].p = ra; } else { if (nodes[ra].rank == nodes[rb].rank) { nodes[rb].rank++; } nodes[ra].p = rb; } } typedef struct ImageSize { int w, h; } ImageSize; typedef struct Coord { int row, col; } Coord; void fus_dfs(const Coord* pt, const Coord* f_pt, FSU_Node* nodes, ImageSize* sz, unsigned char* mp) { int row = pt->row; int col = pt->col; int f_row = f_pt->row; int f_col = f_pt->col; if (row < 0 || row >= sz->h || col < 0 || col >= sz->w) return; int id = row * sz->w + col; int fid = f_row * sz->w + f_col; /* if (vis[id] || mp[id] == '*') return; */ if (nodes[id].vis || mp[id] == '*') return; /* vis[id] = 1; */ nodes[id].vis = 1; if (f_row != -1) { fus_union(id, fid, nodes); } int i, j; Coord neighbor; for (i = -1; i < 2; i++) { for (j = -1; j < 2; j++) { if (!i && !j) continue; neighbor.row = row + i; neighbor.col = col + j; fus_dfs(&neighbor, pt, nodes, sz, mp); } } } /*#define LOCAL*/ int main() { #ifdef LOCAL const char* input_txt = "F:/zhangzhuo/debug/OJ/UVA-572.txt"; freopen(input_txt, "r", stdin); #endif #define MAXN 105 int m, n, cnt, i, j; /* int vis[MAXN*MAXN]; */ unsigned char mp[MAXN*MAXN]; FSU_Node nodes[MAXN*MAXN]; int idx; while (scanf("%d%d", &m, &n) == 2 && m && n) { cnt = 0; /* memset(vis, 0, sizeof(int)*MAXN*MAXN); */ for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { idx = i * n + j; scanf(" %c", &mp[idx]); /* printf("! %c !", mp[idx]); */ } } for (i = 0; i < m*n; i++) { nodes[i].p = idx; nodes[i].rank = 1; nodes[i].vis = 0; } ImageSize im_sz; im_sz.h = m; im_sz.w = n; Coord pt; Coord f_pt; f_pt.row = -1; f_pt.col = -1; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { idx = i * n + j; /* if (!vis[idx] && mp[idx] == '@') { */ if (!nodes[idx].vis && mp[idx] == '@') { /* dfs(i, j, -1, -1); */ pt.row = i; pt.col = j; /* fus_dfs(&pt, &f_pt, nodes, &im_sz, vis, mp); */ fus_dfs(&pt, &f_pt, nodes, &im_sz, mp); cnt++; } } } printf("%d\n", cnt); #ifdef LOCAL for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { idx = i * m + j; /* printf("%3d", vis[idx]); */ printf("%c", mp[idx]); } printf("\n"); } printf("\n"); #endif } return 0; }
這裏的教訓是,若是在雙重for循環中使用變量x、y來表示座標,容易把2維度座標->1維座標的計算算錯。使用row,col能減小犯錯可能;
另外就是數據讀取,這裏改爲%c
,則須要過濾掉換行符\n
,方法是scanf時的格式串首部添加空格:scanf(" %c", &xx)
code