暑假第九场——DFS

感想

在最短路之后学习了深广搜,本想着像上一场一样轻松,用模板答题即可,却大大的想错了。感觉无论是DFS还是BFS都是一种思想,没有确定的模板来使用,所以一开始接触直接懵逼,做了几个题就做不动了,所以来写此博客,梳理一下思路,当然还是用题来做笔记。

经过思考还是把DFS和BFS放在两个博客中


PROBLEM

一、poj2386

Lake Counting

Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 36404 Accepted: 18087

Description

Due to recent rains, water has pooled in various places in Farmer John’s field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water (‘W’) or dry land (‘.’). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors.

Given a diagram of Farmer John’s field, determine how many ponds he has.
Input

  • Line 1: Two space-separated integers: N and M

  • Lines 2..N+1: M characters per line representing one row of Farmer John’s field. Each character is either ‘W’ or ‘.’. The characters do not have spaces between them.

Output

  • Line 1: The number of ponds in Farmer John’s field.

Sample Input

10 12
W……..WW.
.WWW…..WWW
….WW…WW.
………WW.
………W..
..W……W..
.W.W…..WW.
W.W.W…..W.
.W.W……W.
..W…….W.
Sample Output

3

Hint

OUTPUT DETAILS:

There are three ponds: one in the upper left, one in the lower left,and one along the right side.
Source

USACO 2004 November


题意:寻找有多少个水洼,向八个方向寻找。
想法:既然各个水洼是分割开的,那么遍历这些点,当发现’W’时,就DFS,把相连的点去掉(算作’.’),水洼个数加一。

CODE:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <functional>
#include <time.h>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1)
char map[1500][1500];
int m,n;
void DFS(int x,int y)
{
    map[x][y]='.';
    int move[8][2]={{-1,1},{0,1},{1,1},{-1,0},{1,0},{-1,-1},{0,-1},{1,-1}};
    for(int i=0;i<8;i++)
    {
        int a=x+move[i][0];
        int b=y+move[i][1];
        if(map[a][b]=='W'&&a>=0&&a<m&&b>=0&&b<n)
        {
            map[a][b]='.';
            DFS(a,b);
        }
    }
}

int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        int sum=0;
        getchar();
        for(int i=0;i<m;i++)
            scanf("%s",&map[i]);
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                if(map[i][j]=='W')
                {
                    DFS(i,j);
                    sum++;
                }
        printf("%d\n",sum);
    }

}

二、HDU1312

Red and Black

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 21149 Accepted Submission(s): 12897

Problem Description
There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can’t move on red tiles, he can move only on black tiles.

Write a program to count the number of black tiles which he can reach by repeating the moves described above.

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.

There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.

‘.’ - a black tile
‘#’ - a red tile
‘@’ - a man on a black tile(appears exactly once in a data set)

Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).

Sample Input


6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#..@#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
...@...
###.###
..#.#..
..#.#..
0 0

Sample Output

45
59
6
13

Source

Asia 2004, Ehime (Japan), Japan Domestic

Recommend

Eddy | We have carefully selected several similar problems for you: 1016 1010 1372 1242 1253

题意:输入相应的格子的数目,并且标记每个格子的颜色,当遇到黑色的格子时可以踩上,当遇到红色的格子时不能踩上,要求输出从一个起始点出发能够踩到的黑色格子数。
思路跟上一题相同,先找到起点’@’,再DFS。

CODE

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <functional>
#include <time.h>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1)
int m,n,sum;
char map[150][150];
void DFS(int x,int y)
{
    int move[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
    map[x][y]=='#';
    for(int i=0;i<4;i++)
    {
        int a=x+move[i][0];
        int b=y+move[i][1];
        if(a>=0&&a<n&&b>=0&&b<m&&map[a][b]=='.')
        {
            sum++;
            map[a][b]='#';
            DFS(a,b);
        }
    }
}
int main()
{
    while(scanf("%d%d",&m,&n)!=EOF&&m&&n)
    {
        getchar();
        sum=0;
        for(int i=0;i<n;i++)
            scanf("%s",map[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(map[i][j]=='@')
                {
                    DFS(i,j);
                    break;
                }
        printf("%d\n",sum+1);
    }
}

HDU1241与上两题类似,都可以作为练手题,简单,可以初步体会DFS的思想。

三、POJ2531

Network Saboteur

Time Limit: 2000MS Memory Limit: 65536K、Total Submissions: 13442 Accepted: 6521

Description

A university network is composed of N computers. System administrators gathered information on the traffic between nodes, and carefully divided the network into two subnetworks in order to minimize traffic between parts.
A disgruntled computer science student Vasya, after being expelled from the university, decided to have his revenge. He hacked into the university network and decided to reassign computers to maximize the traffic between two subnetworks.
Unfortunately, he found that calculating such worst subdivision is one of those problems he, being a student, failed to solve. So he asks you, a more successful CS student, to help him.
The traffic data are given in the form of matrix C, where Cij is the amount of data sent between ith and jth nodes (Cij = Cji, Cii = 0). The goal is to divide the network nodes into the two disjointed subsets A and B so as to maximize the sum ∑Cij (i∈A,j∈B).

Input

The first line of input contains a number of nodes N (2 <= N <= 20). The following N lines, containing N space-separated integers each, represent the traffic matrix C (0 <= Cij <= 10000).
Output file must contain a single integer – the maximum traffic between the subnetworks.

Output

Output must contain a single integer – the maximum traffic between the subnetworks.

Sample Input

3
0 50 30
50 0 40
30 40 0

Sample Output

90


题意给出n个点(0-n-1),接下来n行,每行有n个数,第i行代表第i-1个数距离n个点的距离,问将这些点分为两部分,两个点集之间的权值最大值为多少。例如样例中讲0,1,2分为两部分(1,3)和(2)两部分,则最长距离为map[1][2]+map[3][2]=90。
想法:从集合中只有元素1开始遍历{1}->{1,2}->{1,2,3}->{1,3}取最大值

CODE

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <functional>
#include <time.h>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1)
int map[25][25];
int f[25];
int n;
int num_max;
void dfs(int num,int sum)
{
    f[num]=1;      //做个标记,知道当前和1在一起的都有谁
    int total=sum;     // sum之前的,total是处理之后的
    //当{1}中添加新元素后,total值肯定要变化,变化如下
    for (int i=1;i<=n;i++)
    {
        if (f[i]==1)
            total-=map[num][i];    //与num在一个集合里面,减去权值
        else
            total+=map[num][i];    //与num不在一个集合里面的,加上权值
    }
    num_max=num_max>total?num_max:total;    //取最大值
    for (int i=num+1;i<=n;i++)
        if(total>sum)
        {
          dfs(i,total);//往{1}集合中不断加点{1}->{1,2}->{1,2,3};
            f[i]=0;       //恢复,第二次{1}->{1,3}->{1,3,4}
        }
}
int main()
{
    while (scanf("%d",&n)==1)
    {
        memset(f,0,sizeof(f));
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            cin>>map[i][j];
        num_max=-10000;
        dfs(1,0);     //将1放入到空集合中
        cout << num_max << endl;
    }

    return 0;
}

未完待续。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS(深度优先搜索)可以用于解决迷宫出口问题。 首先,我们需要将迷宫转化为图,其中每个房间是图中的一个节点,每个房间之间的通道是图中的一条边。我们可以用一个二维数组来表示迷宫,其中0表示墙,1表示通道。 然后,我们可以使用DFS来搜索迷宫。我们从起点开始探索,每次选择一个未被访问的相邻节点进行探索,直到找到出口为止。为了避免陷入死循环,我们需要记录已经访问过的节点。 具体实现可以使用递归或者栈来实现DFS,以下是一个使用递归的示例代码(假设起点为(0,0),出口为(n-1,m-1)): ```python def dfs(x, y, visited, maze): # 判断当前节点是否为出口 if x == len(maze)-1 and y == len(maze[0])-1: return True # 标记当前节点已被访问 visited[x][y] = True # 搜索相邻节点 for dx, dy in [(0,1), (0,-1), (1,0), (-1,0)]: nx, ny = x+dx, y+dy # 判断相邻节点是否合法 if 0 <= nx < len(maze) and 0 <= ny < len(maze[0]) and maze[nx][ny] == 1 and not visited[nx][ny]: # 递归搜索相邻节点 if dfs(nx, ny, visited, maze): return True return False # 测试 maze = [ [1, 0, 1, 1, 1], [1, 0, 1, 0, 1], [1, 0, 1, 0, 1], [1, 1, 1, 0, 1], [0, 0, 0, 0, 1] ] visited = [[False for _ in range(len(maze[0]))] for _ in range(len(maze))] print(dfs(0, 0, visited, maze)) # 输出True,表示存在从起点到出口的路径 ``` 这段代码中,dfs函数的参数分别表示当前搜索的节点坐标、已经访问过的节点、迷宫的二维数组。搜索过程中,我们先判断当前节点是否为出口,如果是,则返回True。然后标记当前节点已被访问,并搜索相邻节点,如果找到了一个相邻节点可以到达出口,则返回True。否则,返回False表示无法到达出口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值