A 中国象棋
一道挺标准的DFS模板,只不过走法换成了走日字。
#include <bits/stdc++.h>
using namespace std;
char g[10][9];
bool book[10][9];
int dx[] = { -2,-1,1,2,2,1,-1,-2 };
int dy[] = { 1,2,2,1,-1,-2,-2,-1 };
bool dfs(int x, int y)
{
book[x][y] = true;
if (g[x][y] == 'T')return true;
for (int i = 0; i < 8; i++)
{
int tx = dx[i] + x, ty = dy[i] + y;
if (tx < 0 || tx >= 10 || ty < 0 || ty >= 9) continue;
if (book[tx][ty]) continue;
if (g[tx][ty] == '#') continue;
if (dfs(tx, ty)) return true;
}
return false;
}
int main()
{
for (int i = 0; i < 10; i++)
cin >> g[i];
for (int i = 0; i < 10; i++)
for (int j = 0; j < 9; j++)
if (g[i][j] == 'S')
if (dfs(i, j))cout << "Yes";
else cout << "No";
return 0;
}
B 踏青
[图片缺失] 原图:https://www.edisoncgh.com/wp-content/uploads/2020/05/image.png
遍历到草丛的时候向四周搜索,将能构成草地的草丛标记。
当走到没有被标记过得草丛时就是新的一片草地,cnt++就行了。
#include <bits/stdc++.h>
#define rep(a, b, c) for (int a = b; a <= c; a++)
using namespace std;
const int INF = 0X7F7F7F7F;
const int LIM = 105;
int n, m, cnt;
char g[LIM+1][LIM+1];
bool vis[LIM+1][LIM+1] = {0};
int dxy[4][2] = {{-1, 0}, {1,0}, {0,-1}, {0,1}};
void dfs(int x, int y)
{
vis[x][y] = 1;
for(int i = 0; i < 4; i++)
{
int dx = x + dxy[i][0];
int dy = y + dxy[i][1];
if(dx >= 1 && dx <= n && dy >= 1 && dy <= m && vis[dx][dy] == 0 && g[dx][dy] == '#')
dfs(dx, dy);
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> g[i][j];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(g[i][j] == '#' && vis[i][j] == 0)
{
cnt++;
dfs(i, j);
}
cout << cnt;
return 0;
}
C 引爆炸弹
跟上一题挺像的。遍历到一个炸弹,就将跟他同行列的炸弹一起递归引爆。
这样每次遍历到一个vis=1的炸弹都一定是第一次遇见且之前没有被引爆的,计数器++就行。
#include<iostream>
using namespace std;
const int LIM = 1005;
char g[LIM][LIM];
int n, m, ans;
void dfs(int x, int y)
{
g[x][y] = 0;
for(int i = 0; i < m; i++)
if(g[x][i] == '1')
dfs(x, i);
for(int i = 0; i < n; i++)
if(g[i][y] == '1')
dfs(i, y);
}
int main()
{
cin >> n >> m;
for(int i = 0;i < n; i++)
cin >> g[i];
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(g[i][j] == '1')
{
dfs(i,j);
ans++;
}
cout << ans;
return 0;
}
E超级书架2
[图片缺失] 原图:https://www.edisoncgh.com/wp-content/uploads/2020/05/image-2.png
#include <bits/stdc++.h>
#define rep(a, b, c) for (int a = b; a <= c; a++)
using namespace std;
const int INF = 0X7F7F7F7F;
int n, s, ans = INF;
int h[110];
void dfs(int now, int len, int sum, int b)
{
if(sum >= b)
ans = min(sum-b, ans);
else
for(int i = now; i <= len; i++)
dfs(i+1, len, sum+h[i], b);
}
int main()
{
cin >> n >> s;
for(int i = 0; i < n; i++) cin >> h[i];
dfs(0, n, 0, s);
cout << ans;
return 0;
}
F自然数拆分
[图片缺失] 原图:https://www.edisoncgh.com/wp-content/uploads/2020/05/image-3.png
挺标准的dfs模板。
因为是按因子个数降序排列,所以核心代码块可以参考dfs模板给出下述伪代码:
for(int i = 1; i < n; i++)//因为是分解因子,所以是严格小于n
{
if 符合条件
{
记录当前因子;
往前一步;
递归调用dfs继续往下找;
回退一步;
}
}
如果画出它的决策树的话,可以很清晰的看见就是走到没法走就回到父亲节点走另一个儿子,相当标准。
#include <iostream>
using namespace std;
int a[30];
int n;
void dfs(int sum, int len, int start)
{
if (n == sum)
{
cout << n << "=" << a[0];
for (int i=1; i<len; i++)
cout << "+" << a[i];
cout << endl;
return;
}
for (int i = 1; i < n; i++)
{
if (sum+i <= n && i >= start)
{
a[len] = i;
len++;
dfs(sum+i, len, i);
len--;
}
}
}
int main()
{
cin >> n;
dfs(0, 0, 1);
return 0;
}