题意:给出一块区域,询问有多少个湖泊?
思路:DFS,对于‘W’,深搜一次,并标记已访问。之后每次对未访问的‘W’做一次深搜。
1 #include<iostream> 2 #include<memory.h> 3 using namespace std; 4 char lake[105][105]; 5 bool vis[105][105]; 6 int n, m; 7 void DFS(int r, int c) 8 { 9 if (r >=n || r<0 || c>=m || c < 0) return; 10 if (lake[r][c] == 'W'&&!vis[r][c]) 11 { 12 vis[r][c] = true; 13 DFS(r + 1, c); 14 DFS(r - 1, c); 15 DFS(r, c + 1); 16 DFS(r, c - 1); 17 DFS(r + 1, c + 1); 18 DFS(r + 1, c - 1); 19 DFS(r - 1, c + 1); 20 DFS(r - 1, c - 1); 21 } 22 } 23 int main() 24 { 25 while (cin >> n >> m) 26 { 27 memset(lake, 0, sizeof(lake)); 28 memset(vis, 0, sizeof(vis)); 29 for (int i = 0; i < n; i++) 30 { 31 for (int j = 0; j < m; j++) 32 { 33 cin >> lake[i][j]; 34 } 35 } 36 int num = 0; 37 for (int i = 0; i < n; i++) 38 { 39 for (int j = 0; j < m; j++) 40 { 41 if (lake[i][j] == 'W' && !vis[i][j]) 42 { 43 DFS(i, j); 44 num++; 45 } 46 } 47 } 48 cout << num << endl; 49 } 50 return 0; 51 }
题意:求从‘@’出发,每次只能从4个方向走,且只能走到‘.’的位置,求全部能走到的个数。
思路:从‘@’出发DFS一遍即可。
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 void f(char **p,int x,int y,int x0,int y0,int &sum); 5 int main() 6 { 7 int x, y; 8 while (cin >> x >> y, x != 0 && y != 0) 9 { 10 char **p = new char *[y]; 11 for (int i = 0; i < y; i++) *(p + i) = new char[x]; 12 int x0, y0; 13 for (int i = 0; i < y; i++) 14 for (int j = 0; j < x; j++) 15 { 16 cin >> p[i][j]; 17 if (p[i][j] == '@') 18 { 19 y0 = i; 20 x0 = j; 21 } 22 } 23 int sum=0; 24 f(p, x0, y0, x, y, sum); 25 cout << sum << endl; 26 for (int i = 0; i < y; i++) delete[]p[i]; 27 delete[]p; 28 p = NULL; 29 } 30 return 0; 31 } 32 void f(char **p, int x, int y, int x0, int y0, int &sum) 33 { 34 if (x >= x0 || x < 0 || y >= y0 || y < 0) return; 35 if (p[y][x] == '#') return; 36 else 37 { 38 sum++; 39 p[y][x] = '#'; 40 f(p, x + 1, y, x0, y0, sum); 41 f(p, x - 1, y, x0, y0, sum); 42 f(p, x, y + 1, x0, y0, sum); 43 f(p, x, y - 1, x0, y0, sum); 44 } 45 }
3、POJ 1321 棋盘问题
题意:在一个n*n的矩阵里放k个棋子,只能放在棋盘区域,同时保证每行每列只有最多只有一个棋子。求方案数
思路:DFS,按行开始放。
1 #include<iostream> 2 using namespace std; 3 int n, k; 4 char m[10][10]; 5 int cnt = 0; 6 bool Judge(int r, int c) 7 { 8 for (int i = 0; i < n; i++) 9 {//判断列是否只有一个 10 if (i == r) continue; 11 if (m[i][c] == '@') return false; 12 } 13 return true; 14 } 15 void DFS(int r, int num) 16 {//按行放 17 if (num == 0) 18 { 19 cnt++; 20 return; 21 } 22 if (r == n)return; 23 for (int i = 0; i < n; i++) 24 { 25 if (m[r][i] == '#') 26 { 27 if (Judge(r, i)) 28 { 29 m[r][i] = '@'; 30 DFS(r + 1, num - 1); 31 m[r][i] = '#'; 32 } 33 } 34 } 35 DFS(r + 1, num);//如果这一行不放棋子 36 } 37 int main() 38 { 39 while (~scanf("%d%d", &n, &k)) 40 { 41 if (n == -1 && k == -1)break; 42 for (int i = 0; i < n; i++) 43 { 44 for (int j = 0; j < n; j++) cin >> m[i][j]; 45 } 46 cnt = 0; 47 DFS(0, k); 48 printf("%d ", cnt); 49 } 50 return 0; 51 }
4、POJ 2251 Dungeon Master(BFS)
题意:在一个三维空间里,询问能否从起点走到终点,若能,请求出最短时间。
思路:BFS,方向为6个。
1 #include<iostream> 2 #include<queue> 3 #include<cstdio> 4 using namespace std; 5 char v[35][35][35];//[k][i][j]第k层第i行第j列 6 struct node 7 { 8 int k; 9 int r; 10 int c; 11 int steps; 12 node(int kk = 0, int rr = 0, int cc = 0,int ss=0):k(kk),r(rr),c(cc),steps(ss){ } 13 }; 14 node st, ed; 15 int L, R, C; 16 int dr[] = {1,-1,0,0,0,0}; 17 int dc[] = {0,0,1,-1,0,0}; 18 int dl[] = {0,0,0,0,1,-1}; 19 int main() 20 { 21 while (~scanf("%d%d%d",&L,&R,&C)) 22 { 23 if (L == 0 && R == 0 && C == 0)break; 24 for (int k = 0; k < L; k++) 25 { 26 for (int i = 0; i < R; i++) 27 { 28 for (int j = 0; j < C; j++) 29 { 30 cin >> v[k][i][j]; 31 if (v[k][i][j] == 'S') st.k = k, st.r = i, st.c = j,st.steps=0; 32 if (v[k][i][j] == 'E') ed.k = k, ed.r = i, ed.c = j; 33 } 34 } 35 } 36 //BFS 37 queue<node>q; 38 q.push(st); 39 v[st.k][st.r][st.c] = '#'; 40 bool Find = false; 41 while (!q.empty()) 42 { 43 node cur = q.front(); 44 q.pop(); 45 if (cur.k == ed.k&&cur.r == ed.r&&cur.c == ed.c) 46 { 47 ed.steps = cur.steps; 48 Find = true; 49 break; 50 } 51 int stp = cur.steps; 52 for (int i = 0; i < 6; i++) 53 { 54 int tr = cur.r + dr[i]; 55 int tc = cur.c + dc[i]; 56 int tl = cur.k + dl[i]; 57 if (tr >= 0 && tr < R&&tc >= 0 && tc < C&&tl >= 0 && tl < L&&v[tl][tr][tc] != '#') 58 { 59 q.push(node(tl, tr, tc, stp + 1)); 60 v[tl][tr][tc] = '#'; 61 } 62 } 63 } 64 if (Find) printf("Escaped in %d minute(s). ", ed.steps); 65 else printf("Trapped! "); 66 } 67 return 0; 68 }
5、HDU 2717/POJ 3278 Catch That Cow
题意:在一个数轴上,给出人和牛的位置,每次人可以从当前位置p走到p+1或p-1或2*p的位置,问能抓到牛的最少移动次数。
思路:BFS,每次选择合法的走法。
1 #include<iostream> 2 #include<queue> 3 #include<memory.h> 4 using namespace std; 5 int n, k; 6 struct node 7 { 8 int pos; 9 int steps; 10 node(int p=0,int stp=0):pos(p),steps(stp){ } 11 }; 12 bool vis[200010]; 13 int main() 14 { 15 while (~scanf("%d%d", &n, &k)) 16 { 17 //BFS(); 18 memset(vis, 0, sizeof(vis)); 19 queue<node>q; 20 q.push(node(n,0)); 21 vis[n] = true; 22 int ans = 0; 23 while (!q.empty()) 24 { 25 node t = q.front(); 26 q.pop(); 27 int pos = t.pos, stps = t.steps; 28 if (pos == k) 29 { 30 ans = stps; 31 break; 32 } 33 if (pos < k) 34 { 35 if(!vis[pos+1])q.push(node(pos + 1, stps + 1)), vis[pos + 1]=true; 36 if(!vis[pos*2])q.push(node(pos * 2, stps + 1)),vis[pos*2]=true; 37 if(pos-1>0&&!vis[pos-1])q.push(node(pos - 1, stps + 1)),vis[pos-1]=true; 38 } 39 else 40 { 41 if(!vis[pos-1])q.push(node(pos - 1, stps + 1)),vis[pos-1]=true; 42 } 43 } 44 printf("%d ", ans); 45 } 46 47 return 0; 48 }
6、POJ 3279 Fliptile
题意:给出一个M*N的矩阵,元素为1或0,每次能够选择一个点反转,同时将其上下左右的点都反转(如果点存在的话),问能使最终矩阵只剩下0时且反转次数最少时的选择反转的点(用矩阵给出)
思路:如果第一行我们要反转的点已经确定,那么第一行的0和1的状态就确定,那么第二行的反转的点就会确定,因为此时只有反转第二行的点才能对第一行的1产生影响。走到最后一行,如果在反转最后一行后最后一行都为0,那么我们可以确定这是一种方案。我们枚举第一行选择反转的点的状态,就能知道最后满足题意的反转的方案。
1 //最多15位,用2进制状态压缩。枚举第一层的反转情况。第一层确定,后面反转状态的都会确定下来 2 #include<iostream> 3 using namespace std; 4 const int maxn = 16; 5 const int maxp = 16 * 16; 6 int init[maxn];//存初始状态 7 int flipstate[maxn];//存反转状态 8 int state[maxn];//存中间的状态 9 int ans[maxn],steps;//存结果 10 int n, m; 11 void DFS(int r, int cnt) 12 { 13 if (r == n) 14 { 15 if (state[n - 1] == 0) 16 { 17 if (cnt < steps) 18 { 19 for (int i = 0; i < n; i++) ans[i] = flipstate[i]; 20 steps = cnt; 21 }//由于我们按照第一行反转状态从小到大DFS,所以如果相等,肯定前面已经保存的字典序小,所以不用再进行判断及赋值操作 22 } 23 return; 24 } 25 flipstate[r] = 0; 26 27 for (int i = m-1; i>=0; --i) 28 {//从左往右遍历 29 if (state[r - 1] & (1 << i))//前一行为1 30 { 31 flipstate[r] |= 1 << i;//该行灯反转 32 state[r - 1] ^= (1 << i);//保存反转后对格子的影响 33 state[r] ^= (1 << i); 34 if (i + 1 <= m - 1) state[r] ^= (1 << (i + 1)); 35 if(i-1>=0) state[r] ^= (1 << (i - 1)); 36 if (r + 1 < n) state[r + 1] ^= (1 << i); 37 cnt++;//反转次数累加 38 } 39 } 40 DFS(r + 1, cnt); 41 } 42 void Solve() 43 { 44 int total = (1 << m) - 1; 45 steps = maxp; 46 for (int st = 0; st <= total; st++) 47 { 48 flipstate[0] = st; 49 memcpy(state, init, sizeof(init)); 50 int cnt = 0; 51 for (int i = m - 1; i >= 0; --i) 52 { 53 if (st&(1 << i)) 54 { 55 state[0] ^= (1 << i); 56 if (i + 1 <= m - 1)state[0] ^= (1 << (i + 1)); 57 if (i - 1 >= 0) state[0] ^= (1 << (i - 1)); 58 state[1] ^= (1 << i); 59 cnt++; 60 } 61 } 62 DFS(1, cnt); 63 } 64 } 65 int main() 66 { 67 while (~scanf("%d%d", &n, &m)) 68 { 69 memset(init, 0, sizeof(init)); 70 for (int i = 0; i < n; i++) 71 { 72 for (int j = m - 1; j >= 0; --j) 73 { 74 int num; 75 scanf("%d", &num); 76 if (num == 1) init[i] |= (1 << j); 77 } 78 } 79 Solve(); 80 if (steps == maxp) printf("IMPOSSIBLE "); 81 else 82 { 83 for (int i = 0; i < n; i++) 84 { 85 for (int j = m - 1; j >= 0; --j) 86 { 87 if (j < m - 1) printf(" "); 88 if (ans[i] & (1 << j))printf("1"); 89 else printf("0"); 90 } 91 printf(" "); 92 } 93 } 94 } 95 return 0; 96 }
7、POJ 1426 Find The Multiple
题意:对于给定的数n,找到一个数是其倍数,同时该数中只含有1或0.
思路:DFS,从1开始枚举,若不是n的倍数,则*10或*10+1,当枚举的数位数超过19位后,直接舍弃。题目能够保证在long long的范围里有解。
1 //对于n,找到一个只包含数字1和0的数,使它为n的倍数 2 #include<iostream> 3 #include<queue> 4 using namespace std; 5 long long ans,n; 6 bool flag = false; 7 void DFS(long long t,int k) 8 { 9 if (flag||k>19) return; 10 if (t%n == 0) 11 { 12 flag = true; 13 ans = t; 14 return; 15 } 16 DFS(t * 10,k+1); 17 if (flag) return; 18 DFS(t * 10 + 1,k+1); 19 } 20 int main() 21 { 22 while(~scanf("%d",&n)) 23 { 24 if (n == 0) break; 25 flag = false; 26 DFS(1,1); 27 printf("%lld ",ans); 28 } 29 30 31 return 0; 32 }
8、POJ 3126 Prime Path(素数变换路径)
题意:给出一个4位素数,在给出一个要求的素数,问通过最少的变换次数(每次只能把当前素数的某一位换成其他数字,同时变换后的数字要求是素数)从初始的素数变换到要求的素数。
思路:先打表判断某一个数是否为素数;然后对于当前一个素数,对其所有位都进行模拟变换,注意最高位不能变换为0,BFS。
1 #include<iostream> 2 #include<queue> 3 using namespace std; 4 const int maxn = 10005; 5 bool isp[maxn]; 6 int prime[maxn], cnt; 7 int ans; 8 void makePrime() 9 { 10 memset(isp, true, sizeof(isp)); 11 isp[0] = isp[1] = false; 12 cnt = 0; 13 for (int i = 2; i < maxn; ++i) 14 { 15 if (isp[i])//是素数 16 { 17 prime[cnt++] = i;//保存该素数 18 } 19 for (int j = 0; j < cnt && i * prime[j] < maxn; ++j) 20 { 21 isp[i * prime[j]] = false;//当前的数乘以所有已算出的素数都不是素数 22 if (i % prime[j] == 0)//如果i能被某一个最小的素数整除,则退出 23 { 24 break; 25 } 26 } 27 } 28 } 29 int a, b; 30 int vis[maxn]; 31 32 void BFS() 33 { 34 queue<int>q; 35 q.push(a); 36 vis[a] = 1; 37 while (!q.empty()) 38 { 39 int v = q.front(); 40 q.pop(); 41 //printf("%d %d ", v, vis[v]); 42 if (v == b) 43 { 44 ans = vis[v]-1; 45 return; 46 } 47 int base1 = 10,base2=1; 48 for (int i = 0; i < 4; i++) 49 { 50 for (int j = 0; j <= 9; j++) 51 { 52 if (v%base1 / base2 == j)continue; 53 if (i == 3 && j == 0)continue; 54 int tmp = v / base1*base1 + v%base2 + j*base2; 55 if (isp[tmp]&&!vis[tmp]) 56 { 57 vis[tmp] = vis[v]+1; 58 q.push(tmp); 59 60 } 61 } 62 base1 *= 10; 63 base2 *= 10; 64 } 65 } 66 67 } 68 int main() 69 { 70 makePrime(); 71 int t; 72 scanf("%d", &t); 73 while (t--) 74 { 75 scanf("%d%d", &a, &b); 76 memset(vis, 0, sizeof(vis)); 77 BFS(); 78 printf("%d ", ans); 79 } 80 return 0; 81 }
9、POJ 3087 Shuffle'm Up
题意:初始有两堆扑克,问能否通过变换得到指定的一堆扑克,若能,求最少次数。
思路:BFS,如果变换后再拆分后的结果某次等于初始状态,说明无法变换到指定的堆。否则,不断进行模拟变换和拆分。
1 #include<iostream> 2 #include<memory.h> 3 using namespace std; 4 char s1[105]; 5 char s2[105]; 6 char des[210]; 7 int main() 8 { 9 int t; 10 int Case = 1; 11 scanf("%d", &t); 12 while (t--) 13 { 14 int c; 15 scanf("%d", &c); 16 scanf("%s", s1); 17 scanf("%s", s2); 18 scanf("%s", des); 19 int cnt = 0; 20 char t1[105], t2[105],ts[210]; 21 memcpy(t1, s1, sizeof(s1)); 22 memcpy(t2, s2, sizeof(s2)); 23 while (1) 24 { 25 int len = 0; 26 for (int i = 0; i < c; i++) 27 { 28 ts[len] = t2[i]; 29 len++; 30 ts[len] = t1[i]; 31 len++; 32 } 33 cnt++; 34 ts[len] = '