UVA572 Oil Deposits DFS求解

小白书上经典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