A
题意:问可以到达多少地方.'@'为起点, ' . '为路,可以到达, ' # '为墙,不能通过.
思路:简单题,既可以用深搜,也可以用广搜,广搜是可以用C++里的queue,如果是C的话也可以实现其功能,其实也没有多复杂.还有一个小技巧,搜索过的地方可以用'#'标记!
代码:
#include<stdio.h>
#include<memory.h>
#include<string.h>
char a[22][22];
int b[22][22];
int sum = 1;
void dfs(int x, int y)
{
b[x][y] = 1;
if (a[x - 1][y] == '.'&&b[x - 1][y] == 0)
{
sum++;
dfs(x - 1, y);
}
if (a[x + 1][y] == '.'&&b[x + 1][y] == 0)
{
sum++;
dfs(x + 1, y);
}
if (a[x][y - 1] == '.'&&b[x][y - 1] == 0)
{
sum++;
dfs(x, y - 1);
}
if (a[x][y + 1] == '.'&&b[x][y + 1] == 0)
{
sum++;
dfs(x, y + 1);
}
}
int main()
{
int i, j, m, n;
while (scanf("%d %d", &n, &m) != EOF, m + n)
{
gets(a[1]);
memset(b, 0, sizeof(b));
memset(a, '\0', sizeof(a));
sum = 1;
int x = 0, y = 0;
for (i = 1; i <= m; i++)
{
for (j = 1; j <= n; j++)
{
scanf("%c", &a[i][j]);
if (a[i][j] == '@')
{
x = i, y = j;
}
}
getchar();
}
dfs(x, y);
printf("%d\n", sum);
}
return 0;
}
B
对于一个图,八个方向代表相邻,求出相邻的块的个数.BFS/DFS搜索,我们对图整个进行扫描,一旦发现了'W‘,我们进入搜索函数,对周边的额八个方向整体进行扫描,并同步修改图,当我们扫描完整个图的时候,我们也就计算出来了块的个数
#include<stdio.h>
#include<string.h>
int m, n, x1, x2;
char a[105][105];
int d[8][2] = { 0, 1, 1, 1, 1, 0, 1, -1, 0, -1, -1, -1, -1, 0, -1, 1 };
void dfs(int x, int y)
{
a[x][y] = '.';
int i;
for (i = 0; i < 8; i++)
{
x1 = x + d[i][0];
x2 = y + d[i][1];
if (x1 <= m&&x1 >= 1 && x2 <= n&&x1 >= 1 && a[x1][x2] == 'W')
dfs(x1, x2);
}
}
int main()
{
int i, j, r;
scanf("%d %d", &m, &n);
gets(a[1]);
r = 0;
for (i = 1; i <= m; i++)
gets(a[i] + 1);
for (i = 1; i <= m; i++)
{
for (j = 1; j <= n; j++)
{
if (a[i][j] == 'W')
{
dfs(i, j);
r++;
}
}
}
printf("%d\n", r);
return 0;
}
C
中文题,没什么好说的。
回溯法,其实就是<递归枚举>,再说得通俗一点,其实就是一种<暴力>。 因此,这种解法时间耗费其实是指数级增长。基于此,题目中的N(递归形成的树的深度)一般不会给太大。
首先我们可以明确这是一个深度搜索的题目,与八皇后问题相似。我们建立一个函数DFS用来累计可行的方案数,我们走过一列我们就把它标记下来下次的时候就不可以再摆放在这一列,然后就从下一行开始寻找可行的地方,直到我们摆放的棋子数与我们被要求摆放的棋子数相同时,我们就将方案数进行一次++,然后在进行递归下去。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char mp[9][9];
int v[9];//标记每一列是否放棋子
int n, k, w, r;//棋盘大小,棋子数,已经用了的棋子数,方案数
void dfs(int x)//x表示行数
{
if (w == k)
{
r++; return; //判断是否棋子已经用完,如果用完,记录方案数加1,
}
if (x >= n)return;
for (int i = 0; i<n; i++)
{
if (v[i] != 1 && mp[x][i] == '#')//标记数组仅仅标记某一列上是否有棋子,因为每次递归下一列,所以每一列不会有冲突,只需判断这一列上是否有其他棋子
{//满足要求的条件是:这个位置是#,这个位置没有被标记过
v[i] = 1;//如果这一列没有棋子,可以就放上
w++;//用了的棋子加1;
dfs(x + 1);//搜索下一行
w--;//返回到了上一层x,这一层不是x+1,是x,对这一层解除标记;
v[i] = 0;//同上
}
}
dfs(x + 1);//这一层没有符合要求的,只能跳过这层了,所以,层数增加,棋子数量不增加;
}
int main()
{
while (cin >> n >> k)
{
if (n == -1 && k == -1)
return 0;
memset(mp, 0, sizeof(mp));
memset(v, 0, sizeof(v));
for (int i = 0; i<n; i++)
cin >> mp[i];
w = 0; r = 0;//记录满足情况的数目;//记录放入棋子的个数
dfs(0);//从第一层开始搜索第一个适合放棋子的地方;
cout << r << endl;
}
}
D
n最大才15,每一个数字可能是顺时针,也可能是逆时针转的,复杂度O(2^n)
可以用二进制枚举也可以dfs。
代码
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
typedef long long ll;
int a[20];
int n;
int flag = 0;
void dfs(int sum, int x)
{
if (x > n)//层数搜索完了
{
if (sum % 360 == 0)
flag = 1;//满足条件直接记录可以输出YES
return;
}
dfs(sum + a[x], x + 1);//总共个方向,一个加,一个减
dfs(sum - a[x], x + 1);
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
dfs(0, 1);//初始和为0,从第一层开始搜索
if (flag)
puts("YES");
else
puts("NO");
return 0;
}