DFS个人总结
1.DFS作为基础入门算法,在基础题上,就只有短短几行,但是在复杂题上千变万化,(暂时还没刷到那儿,后面遇到再来总结),我最先接触的第一道题,就是走迷宫,但是DFS不仅仅局限于走迷宫。
1.
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.
There are three ponds: one in the upper left, one in the lower left,and one along the right side.
简言之,这道题就是问有多少块
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<map>
#include<stdio.h>
#define maxn 105
using namespace std;
int m,n,vis[maxn][maxn],cas;//vis标记数组可能是标记走过的,可能是标记让他不能重复使用。
char s[maxn][maxn];
int dx[] = {-1,-1,-1,1,1,1,0,0};//方向数组,管上下的
int dy[] = {1,-1,0,0,-1,1,-1,1};//方向数组,管左右的
/*这是八个方向的,上下左右四个方向的就是dx[] = {-1,1,0,0};dy[] = {0,0,-1,1};出题可能就是在方向数组上有变化。
void dfs(int x,int y){
for(int i = 0 ; i < 8 ; i++){
int xx = x + dx[i];//让坐标上下移动
int yy = y + dy[i];//让坐标左右移动
if(xx > m || xx < 0 || yy > n || yy < 0 || vis[xx][yy] || s[xx][yy] != 'W') continue;//判定越界和不能走
vis[xx][yy] = 1;//标记走过
dfs(xx,yy);//递归。
}
}
int main(){
while(~scanf("%d%d",&m,&n)){
for(int i = 0 ; i < m ; i++){
scanf("%s",s[i]);
}
for(int i = 0 ; i < m ; i++){
for(int j = 0 ; j < n ; j++){
if(s[i][j] == 'W' && vis[i][j] == 0){
dfs(i,j);
cas++;
}
}
}
printf("%d\n",cas);
}
return 0;
}
2.素数环这道题也着实经典
A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.
Note: the number of first circle should always be 1.
Input
n (0 < n < 20).
Output
The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
You are to write a program that completes above process.
Print a blank line after each case.
Sample Input
6
8
Sample Output
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
这道题,唉,感觉没什么好说的,直接贴代码。
#include<iostream>
#include<math.h>
#include<algorithm>
#include<bits/stdc++.h>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
int vis[25],a[25];
int m,n;
//对是否是素数的判断
int prime(int x){
for(int i = 2 ; i <= sqrt(x) ; i++){
if(x % i == 0) return 0;
}
return 1;
}
int dfs(int n){
if(n == m){
if(prime(1 + a[m])){
for(int i = 1 ; i <= m ; i++){
printf("%d",a[i]);
if(i != m) printf(" ");
}
printf("\n");
}
}//出口
for(int i = 2 ; i <= m ; i++){
if(prime(a[n] + i) && !vis[i]){
a[n + 1] = i;
vis[i] = 1;
dfs(n + 1);
vis[i] = 0;//标记回来,让他有下一次被使用的机会 }
}
}
int main(){
int k = 1;
a[1] = 1;
while(~scanf("%d",&m)){
printf("Case %d:\n",k++);
dfs(1);
printf("\n");
}
//printf("\n");
}
还有一道题也很经典,类似八皇后这样的问题。
Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall.
A blockhouse is a small castle that has four openings through which to shoot. The four openings are facing North, East, South, and West, respectively. There will be one machine gun shooting through each opening.
Here we assume that a bullet is so powerful that it can run across any distance and destroy a blockhouse on its way. On the other hand, a wall is so strongly built that can stop the bullets.
The goal is to place as many blockhouses in a city as possible so that no two can destroy each other. A configuration of blockhouses is legal provided that no two blockhouses are on the same horizontal row or vertical column in a map unless there is at least one wall separating them. In this problem we will consider small square cities (at most 4x4) that contain walls through which bullets cannot run through.
The following image shows five pictures of the same board. The first picture is the empty board, the second and third pictures show legal configurations, and the fourth and fifth pictures show illegal configurations. For this board, the maximum number of blockhouses in a legal configuration is 5; the second picture shows one way to do it, but there are several other ways.
Your task is to write a program that, given a description of a map, calculates the maximum number of blockhouses that can be placed in the city in a legal configuration.
Input
The input file contains one or more map descriptions, followed by a line containing the number 0 that signals the end of the file. Each map description begins with a line containing a positive integer n that is the size of the city; n will be at most 4. The next n lines each describe one row of the map, with a ‘.’ indicating an open space and an uppercase ‘X’ indicating a wall. There are no spaces in the input file.
Output
For each test case, output one line containing the maximum number of blockhouses that can be placed in the city in a legal configuration.
Sample Input
4
.X..
….
XX..
….
2
XX
.X
3
.X.
X.X
.X.
3
…
.XX
.XX
4
….
….
….
….
0
Sample Output
5
1
5
2
4
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<string>
#include<string.h>
using namespace std;
int m,vis[10][10],sum;
char s[10][10];
int check(int x,int y){
for(int i = x + 1 ; i < m && s[i][y] != 'X'; i++){
if(vis[i][y]) return 0;
}
for(int i = x - 1 ; i >= 0 && s[i][y] != 'X'; i--){
if(vis[i][y]) return 0;
}
for(int i = y + 1 ; i < m && s[x][i] != 'X'; i++){
if(vis[x][i]) return 0;
}
for(int i = y - 1 ; i >= 0 && s[x][i] != 'X'; i--){
if(vis[x][i]) return 0;
}
return 1;
}
void dfs(int x,int i,int cas){ //x表示行数,cas表示有多少个,i表示列
if(x == m){
//cout<<cas<<endl;
sum = max(sum,cas);
return;
}
for(int j = i ; j < m ; j++){
if(s[x][j] != 'X' && check(x,j)){
vis[x][j] = 1;
dfs(x,j + 1,cas + 1);
vis[x][j] = 0;
}
}
//cout<<cas<<endl;
dfs(x + 1,0,cas);
}
int main(){
while(~scanf("%d",&m) && m){
sum = 0;
memset(vis,0,sizeof(vis));
for(int i = 0 ; i < m ; i++){
scanf("%s",s[i]);
}
dfs(0,0,0);
cout<<sum<<endl;
}
return 0;
}
感觉前面就把话说的差不多了。这道题没什么好说的了。其实有话说,但是找不到言语表达,算了,自行体会吧。