小白书上经典DFS题目。

1. 递归实现

// 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循环,本质上还是栈,但是避免了递归时嵌套产生的开销造成的潜在风险。

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,函数指针

#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+并查集实现

#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+并查集+不使用全局变量+简单封装为结构体

修改自 UVA572 (并查集解法) 。这种写法有点问题:已经用了dfs,dfs里用并查集多此一举,如果用并查集就不应该递归调用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)

6. 并查集,去掉了DFS

思路:遍历每个像素点,每个像素点用并查集算法合并周边8邻域中为'@'的像素点。再次遍历,统计每个'@'像素对应的等价类(root节点)的值。第三次遍历,把第二次统计的值当中cnt数大于0的累计,就是区域个数。在统计连通域个数的时候顺带把每个连通域id(像素的parent值)修改为从1开始严格单调增的序列,开启LOCALLOCAL_DEBUG宏可以看到。

和通常用的模板写法略有差别,比如返回root的递归终止条件,比如root初值。

不得不说,uDebug是个好东西。

#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h> typedef struct FSU_Node {
int p; /* parent id */
int rank;
} 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;
}
} /* #define LOCAL */
/* #define LOCAL_DEBUG */
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, k; int shift_x[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int shift_y[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; unsigned char mp[MAXN*MAXN];
FSU_Node nodes[MAXN*MAXN]; int idx; while (scanf("%d%d", &m, &n) == 2 && m && n) {
cnt = 0;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
idx = i * n + j;
scanf(" %c", &mp[idx]);
}
}
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
idx = i * n + j;
nodes[idx].p = idx;
nodes[idx].rank = 1;
}
} for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
idx = i * n + j;
if (mp[idx] != '@') continue;
for (k = 0; k < 8; k++) {
int row = i + shift_x[k];
int col = j + shift_y[k];
int neighbor_idx = row * n + col;
if (row < 0 || row >= m || col < 0 || col >= n || mp[neighbor_idx] != '@') continue;
fus_union(idx, neighbor_idx, nodes);
}
}
} int bowl[MAXN*MAXN] = { 0 };
int label_cnt = 0;
for (i = 0; i < m*n; i++) {
if (mp[i] != '@') continue;
int t = fus_find(i, nodes);
nodes[i].p = t;
if (bowl[t] == 0) {
label_cnt++;
bowl[t] = label_cnt;
}
}
printf("%d\n", label_cnt); #ifdef LOCAL_DEBUG
/* print out debug info */
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
idx = i * n + j ;
if (mp[idx] == '@') {
/* printf("%3d", fus_find(idx, nodes)); */
/* printf("%3d", nodes[idx].p); */
printf("%3d", bowl[nodes[idx].p]);
}
else {
printf("%3c", '*');
}
}
printf("\n");
}
printf("\n");
#endif } return 0;
}

UVA572 Oil Deposits DFS求解的更多相关文章

  1. UVa572 Oil Deposits DFS求连通块

      技巧:遍历8个方向 ; dr <= ; dr++) ; dc <= ; dc++) || dc != ) dfs(r+dr, c+dc, id); 我的解法: #include< ...

  2. HDOJ(HDU).1241 Oil Deposits(DFS)

    HDOJ(HDU).1241 Oil Deposits(DFS) [从零开始DFS(5)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架 ...

  3. Oil Deposits(dfs)

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  4. HDU 1241 Oil Deposits DFS(深度优先搜索) 和 BFS(广度优先搜索)

    Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...

  5. HDU 1241 Oil Deposits (DFS/BFS)

    Oil Deposits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  6. HDU-1241 Oil Deposits (DFS)

    Oil Deposits Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total ...

  7. HDU_1241 Oil Deposits(DFS深搜)

    Problem Description The GeoSurvComp geologic survey company is responsible for detecting underground ...

  8. UVa 572 Oil Deposits(DFS)

     Oil Deposits  The GeoSurvComp geologic survey company is responsible for detecting underground oil ...

  9. [POJ] 1562 Oil Deposits (DFS)

    Oil Deposits Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16655   Accepted: 8917 Des ...

随机推荐

  1. JS 生成随机字符串 随机颜色

    使用Math.random()生成随机数 0.7489584611780002数字的.toString(n) 将数字转换为 n 进制的字符串 n取值范围(0~36)"0.vbpjw8lipf ...

  2. EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之点播分享

    背景介绍 EasyDSS流媒体服务器软件,提供一站式的视频上传.转码.点播.直播.时移回放等服务,极大地简化了开发和集成的工作.其中,点播功能主要包含:上传.转码.分发.直播功能,主要包含:直播.录像 ...

  3. LeetCode_448. Find All Numbers Disappeared in an Array

    448. Find All Numbers Disappeared in an Array Easy Given an array of integers where 1 ≤ a[i] ≤ n (n  ...

  4. EF Core使用遇到的问题

    目录 EF Core速度问题 问题描述 EF使用方法1,每一行存储一次(400条/s) EF使用方法2,链接不释放 (40条/s) EF使用方法3,多次add,一次SaveChanges(400条/s ...

  5. 启动Oracle 12c数据库实例

    启动Oracle 12c数据库实例 启动Oracle数据库实例,主要分为两步:第一步,启动监听:第二步,启动数据库实例. 1. 切换到oracle用户- su oracle- cd - source ...

  6. AspNetCore 2.2 新特性---HealthCheck

    网站部署上线后, 总是担心网站是否工作正常, 内存压力是否很大, CPU是否超负荷了?当然, 我们有一大套系统, perfromance counter, 监控软件来监视运维生产系统.但是这些第三方软 ...

  7. 简单使用Moq框架

    Moq框架简单使用   系列目录 Moq库简介及安装 Moq简介 Moq是.net平台下的一个非常流行的模拟库,只要有一个接口它就可以动态生成一个对象,底层使用的是Castle的动态代理功能. 它的流 ...

  8. 不同版本的ArcMap在Oracle中创建镶嵌数据集的不同行为

    如果不同版本的ArcMap连接到同一个Oracle数据库上,分别执行"创建镶嵌数据集",它们的行为是一样的吗? 答案是:不一样,会有细微的差别 在本例中,ArcMap的版本分别是1 ...

  9. 腾讯云直播+点播全线产品支持AV1,带来极致视频体验

    日前,腾讯视频云直播.点播.媒体处理全线产品均已支持AV1标准,据悉,腾讯云也是国内首家直播+点播同时支持AV1视频处理业务的公有云厂商. 据悉,AV1(Alliance for Open Media ...

  10. JavaEE 期末总结

    struts2部分 一.struts2框架的集成: 1.web.xml配置struts2过滤器:前端控制器.核心控制器 如果有多个过滤器,需要将该过滤器放置到最后一个 2.struts.xml配置:主 ...