暑假第九场——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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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=0&&bmap[a][b]='.';
            DFS(a,b);
        }
    }
}

int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        int sum=0;
        getchar();
        for(int i=0;iscanf("%s",&map[i]);
        for(int i=0;ifor(int j=0;jif(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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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=0&&bmap[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;iscanf("%s",map[i]);
        for(int i=0;ifor(int j=0;jif(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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
}

未完待续。。。

你可能感兴趣的:(DFS,BFS)