DFS大法好

A - Oil Deposits
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Description
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.

Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.

Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.

Sample Input
1 1
*
3 5
@@*
@
@@*
1 8
@@**@*
5 5
**@
@@@
@*@
@@@*@
@@**@
0 0

Sample Output
0
1
2
2

本题是求连通块个数问题,采用DFS。mmap数组用来存储地图。inx数组用来保存对应地图位置是属于哪一个连通块,同时起到判断块是否已经被查找过的作用。思路是,对于图上每一个位置进行dfs搜索,方向有八个。计数变量只有在发现新的油块且该块不与先前的任意块联通时才增加。

#include "string"
#include <cstdio>
#include "iostream"
using namespace std;


char mmap[103][103];   //用来存储地图
int inx[103][103];     //标记地图中对应位置是否已被查找过
int m,n;

void dfs(int i,int j,int cnt)
{
    if(i<0||i>=m||j<0||j>=n) return;     //如果超出地图范围
    if(inx[i][j]>0||mmap[i][j]!='@') return;  //该块已经被访问过或该块不是oil pocket


    inx[i][j]=cnt;
    for(int dr=-1;dr<=1;dr++)   //遍历各个方向
        for(int dc=-1;dc<=1;dc++)
        {
            if (dr!=0||dc!=0) dfs(i+dr,j+dc,cnt);
        }
}


int main()
{
    while(scanf("%d %d",&m,&n)!=EOF)
    {
        if(m==0&&n==0) return 0;



        for(int i=0;i<m;i++) scanf("%s",mmap[i]); // 读入地图
        memset(inx,0,sizeof(inx));     //标记数组清零 默认状态为0 没有查找过
        int cnt=0;


        for(int i=0;i<m;i++)      //查找一个有油的块 以此为起点做dfs搜索
            for(int j=0;j<n;j++)
            {
                if(mmap[i][j]=='@'&&inx[i][j]==0)
                    dfs(i,j,++cnt);    //判断该块与先前所有块不连通 计数变量+1
            }
        cout<<cnt<<endl;

   }
    return 0;
}

B - Red and Black
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
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

该题我用的思路和A题很像,也是用两个数组一个保存地图另一个数组标记该块是否已经被走过。从一个点出发每个可走的方向都尝试一遍,如果要走到块是可走的(没有跑出地图),同时还没有被走过,那么可走的块数+1。

#include "cstdio"
#include "string"
#include "iostream"
using namespace std;

int m, n;
int inx[23][23];
char mmap[23][23];
int cnt = 0;
void dfs(int r, int w)
{
    //dfs喜闻乐见地把每个方向都走一遍
    //如果当前位置还没有走过 并且是‘.‘可走的 那么可走的块数+1 以该点为起点继续dfs
    if (r+1<n&&mmap[r + 1][w] == '.'&&inx[r + 1][w] == 0) { cnt++; inx[r + 1][w] = 1; dfs(r + 1, w); }
    //同上
    if (r-1>=0&&mmap[r - 1][w] == '.'&&inx[r - 1][w] == 0) { cnt++; inx[r - 1][w] = 1; dfs(r - 1, w); }
    if (w+1<m&&mmap[r][w + 1] == '.'&&inx[r][w + 1] == 0) { cnt++; inx[r][w + 1] = 1; dfs(r, w + 1); }
    if (w-1>=0&&mmap[r][w - 1] == '.'&&inx[r][w - 1] == 0) { cnt++; inx[r][w - 1] = 1; dfs(r, w - 1); }
}

int main()
{
    while (scanf("%d %d", &m, &n) != EOF)
    {
        if (m == 0 && n == 0) return 0;

        for (int i = 0; i<n; i++)
            scanf("%s", mmap[i]);
        memset(inx, 0, sizeof(inx));   //标记数字全部设置为0 意为还没走过  如果值为1说明当前位置已经被走过
        int i, j;
        int mi, mj;
        for (i = 0; i<n; i++)   //将整个图遍历一遍 找到起点 记录坐标 同时将该点设为已走过
            for (j = 0; j<m; j++)
            {
                if (mmap[i][j] == '@')
                {
                    inx[i][j] = 1;
                    cnt++;
                    mi = i;
                    mj = j;

                }
            }
        dfs(mi, mj);//从起点出发

        cout << cnt << endl;

        cnt = 0;

    }
}

C - Tempter of the Bone
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Description
The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking. He realized that the bone was a trap, and he tried desperately to get out of this maze.

The maze was a rectangle with sizes N by M. There was a door in the maze. At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second). Therefore the doggie had to arrive at the door on exactly the T-th second. In every second, he could move one block to one of the upper, lower, left and right neighboring blocks. Once he entered a block, the ground of this block would start to sink and disappear in the next second. He could not stay at one block for more than one second, nor could he move into a visited block. Can the poor doggie survive? Please help him.

Input
The input consists of multiple test cases. The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively. The next N lines give the maze layout, with each line containing M characters. A character is one of the following:

‘X’: a block of wall, which the doggie cannot enter;
‘S’: the start point of the doggie;
‘D’: the Door; or
‘.’: an empty block.

The input is terminated with three 0’s. This test case is not to be processed.

Output
For each test case, print in one line “YES” if the doggie can survive, or “NO” otherwise.

Sample Input
4 4 5
S.X.
..X.
..XD
….
3 4 5
S.X.
..X.
…D
0 0 0

Sample Output
NO
YES

用DFS尝试每一条可以从起点走到终点的路径,并记录时间。注意剪枝,否则会超时。这里写图片描述

#include<iostream>
#include<cmath>
using namespace std;
char map[10][10];
int flag, Xnum, Sx, Sy, Dx, Dy;
int n, m, t;
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

void DFS(int x, int y, int time)
{
    if (x<=0 || x>n || y<=0 || y>m) return;
    if (flag == 1) return;  //马上中断 一步步return回去
    if (x == Dx && y == Dy && time == t)
    {
        if(time == t)
            flag = 1;//找到可行解了
        return;
    }

    int temp = (t - time) - abs(x - Dx) - abs(y - Dy);//奇偶性剪枝
    if(temp<0 || temp & 1)  return;

    for (int i = 0; i<4; i++)
    {
        int x1 = x + dir[i][0];
        int y1 = y + dir[i][1];
        if (map[x1][y1] != 'X')
        {
            map[x1][y1] = 'X';
            DFS(x1, y1, time + 1); //注意这里传递给dfs的第三个参数值是time+1 而原来的time不受影响得以保留
            map[x1][y1] = '.';
        }
    }
    return;
}


int main()
{
    while (cin>>n>>m>>t)
    {
        if(n==0&&m==0&&t==0) break;
        Xnum = 0;
        for (int i = 1; i<=n; i++)
        {
            for (int j = 1; j<=m; j++)
            {
                cin>>map[i][j];
                //记录起点终点
                if (map[i][j] == 'S')
                {
                    Sx = i;
                    Sy = j;
                }
                if (map[i][j] == 'D')
                {
                    Dx = i;
                    Dy = j;
                }
                if (map[i][j] == 'X')
                    Xnum ++;    //计算可走的格子个数
            }
        }
        flag = 0;
        map[Sx][Sy] = 'X';

        if (n * m - Xnum <= t)//提前判断t过大 格子不够走
        {
            cout<<"NO"<<endl;
            continue;
        }
        DFS(Sx, Sy, 0);
        if (flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值