1. 深度优先搜索DFS:
例1:给定整数a0,a1….an,判断是否可以从中选出若干数,使它们的和恰好为K。
#include<stdio.h> bool DFS ( int i, int sum ) //已从ai之前所有项中得到和sum,现对a[i]进行判断。 { if ( i==n ) return sum==k; if ( DFS ( i+1, sum ) ) return true; if ( DFS ( i+1, sum+a[i] ) ) return true; return false ; } void main ( ) { if ( DFS ( 0, 0 ) ) printf ( "yes " ); else printf ( " no " ) ; }
例2.剪格子游戏
在3*3的格子中填一些数,使得左上角的数之和等于除左上角外的所有数之和。
存在多种答疑方法时请选择左上角格子数最小的情况
1 #include <stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int map[20][20], vis[20][20], s, n, m; 7 int to[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1 }; 8 int dfs(int x, int y, int sum) 9 { 10 if (sum == s) 11 return 1; 12 int ans = 0; 13 for (int i = 0; i < 4; i++) 14 { 15 int tx = x + to[i][0]; 16 int ty = y + to[i][1]; 17 if (tx >= 0 && tx < n&&ty >= 0 && ty < m) 18 { 19 if (!vis[tx][ty] && map[tx][ty] + sum <= s) 20 { 21 vis[tx][ty] = 1; 22 ans = dfs(tx, ty, map[tx][ty] + sum); 23 if (ans) 24 return ans + 1; 25 vis[tx][ty] = 0; 26 } 27 } 28 } 29 return 0; 30 } 31 int main() 32 { 33 int i, j; 34 int sum = 0; 35 cin >> m >> n; 36 for (i = 0; i < n; i++) 37 { 38 for ( j = 0; j < m; j++) 39 { 40 cin >> map[i][j]; 41 sum += map[i][j]; 42 } 43 44 } 45 if (sum % 2) 46 printf("0 "); 47 else if (map[0][0] == sum / 2) 48 printf("1 "); 49 else 50 { 51 s = sum / 2; 52 memset(vis, 0, sizeof(vis)); 53 vis[0][0] = 1; 54 printf("%d ", dfs(0, 0, map[0][0])); 55 } 56 return 0; 57 }
2.深度优先搜索BFS:
在一个二维的格子迷宫计算最短路径
学霸的迷宫:
第一行n,m为迷宫的长宽。接下来n行,每行m个数,数之间没有间隔,为0或1的一个,0表示可以通过,1表示不可以。假设你现在已经在迷宫坐标(1,1)的地方,即左上角,迷宫出口在(m,n)。每次移动时只能向上下左右4个方向移动到另外一个可以通过的格子里,每次移动算一步。数据保证(1,1),(n,m)课通过。
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 const int N = 500 + 10; 8 char map[N][N]; 9 int n, m; 10 bool book[N][N]; 11 struct Node{ 12 int x, y, t; 13 string s; 14 }node, tmp; 15 char c[6] = "DLRU"; 16 int step[4][2] = { { 1, 0 }, { 0, -1 }, { 0, 1 }, { -1, 0 } }; //字典序顺序 下左右上 {U,D,L,R} 17 queue<Node> q; 18 int main() 19 { 20 int i, j; 21 while (cin >> n >> m){ 22 for (i = 1; i <= n; i++) 23 for (j = 1; j <= m; j++){ 24 cin >> map[i][j]; 25 book[i][j] = 0; 26 } 27 28 node.x = 1; 29 node.y = 1; 30 node.t = 0; 31 node.s = ""; 32 q.push(node); 33 while (!q.empty()){ 34 tmp = q.front(); 35 if (tmp.x == n&&tmp.y == m) 36 break; 37 q.pop(); 38 for (i = 0; i<4; i++){ 39 int a = tmp.x + step[i][0]; 40 int b = tmp.y + step[i][1]; 41 if (a<1 || a>n || b<1 || b>m || book[a][b] || map[a][b] == '1') 42 continue; 43 book[a][b] = 1; 44 node.x = a; 45 node.y = b; 46 node.t = tmp.t + 1; 47 node.s = tmp.s + c[i]; 48 q.push(node); 49 } 50 } 51 cout << tmp.t << endl; 52 cout << tmp.s << endl; 53 } 54 return 0; 55 }
3.剪枝
若已知从当前状态无论如何转移都不会存在解,则直接跳过,不再继续搜索,称为剪枝。
如:在例1的搜索过程中,只要sum超过K,则不再继续搜索。
100
例4 带分数(蓝桥杯:历届试题)
100可以表示为带分数的形势:100=3+69258/714
还可以表示为:100=82+3546/197
带分数中数字1~9分别出现且只出现一次(不包含0)。
累死这样的分数100中有11中表示法
现将这些用代码表示出来
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 int visit[10]; 5 int a[10]; 6 int kind = 0; 7 int sum(int begin, int end) 8 {int s = 0; 9 for (int i = begin; i <= end; i++) 10 s = s * 10 + a[i]; 11 return s; 12 } 13 void check(int a[], int value) 14 {int num = 0, temp = value; 15 for (int temp = value; temp != 0; temp = temp / 10) num++; 16 for (int k = 1; k <= num; k++) 17 {int left = sum(1, k); 18 if (left >= value) return; 19 for (int j = 5 + k / 2; j<9; j++) 20 {int top = sum(k + 1, j); 21 int down = sum(j + 1, 9); 22 if (top>down&&top%down == 0 && value == left + top / down) 23 kind++; 24 } 25 } 26 } 27 void dfs(int start, int value) 28 { if (start>9) 29 {check(a, value); } 30 else{ 31 for (int i = 1; i <= 9; i++) 32 { if (!visit[i]) 33 {a[start] = i; 34 visit[i] = 1; 35 dfs(start + 1, value); 36 visit[i] = 0; } 37 } 38 39 } 40 } 41 int main() 42 {int value; 43 memset(visit, 0, sizeof(visit)); 44 memset(a, 0, sizeof(a)); 45 scanf("%d", &value); 46 dfs(1, value); 47 printf("%d ", kind); 48 return 0; 49 }