20200203DLUT寒假训练赛div2-简单搜索专场
:比赛地址
A - Find The Multiple
简单的dfs水题,主要是取10x和10x+1两种情况,并且注意函数存储数字必须得用unsigned long long 否则会数据溢出,出现错误
#include<cstdio>
int n;
bool dfs(unsigned long long int sum, int x)
{
if (sum % n == 0)
{
printf("%llu\n", sum);
return 1;
}
if (x == 19)
return 0;
if (dfs(sum * 10, x + 1))
return 1;
if (dfs(sum * 10 + 1, x + 1))
return 1;
return 0;
}
int main(void)
{
while (~scanf("%d", &n) && n)
{
dfs(1, 0);
}
}
B - A Knight’s Journey
国际象棋的马走的规则和中国象棋一样走日,因此要枚举他能走的8个方向,但是为了让输出结果字典序最小,我们首先得让y值每次最小,其次是x,并且由于全部都能走完所以从A1点开始搜索
#include<cstdio>
#include<cstring>
int p, q;
int dir[8][2] = { -1,-2,1,-2,-2,-1,2,-1,-2,1,2,1,-1,2,1,2 };
bool vis[8][8];
int steps[64];
bool dfs(int x, int y, int cnt)
{
if (cnt == p * q)
{
for (int i = 0; i < cnt; ++i)
printf("%c%d", steps[i] % q + 'A', steps[i] / q + 1);
printf("\n");
return 1;
}
for (int i = 0; i < 8; ++i)
{
int tx = x + dir[i][0], ty = y + dir[i][1];
if (vis[tx][ty] || tx < 0 || ty < 0 || tx >= p || ty >= q)
continue;
vis[tx][ty] = 1;
steps[cnt] = tx * q + ty;
if (dfs(tx, ty, cnt + 1))
return 1;
vis[tx][ty] = 0;
}
return 0;
}
int main(void)
{
int T;
scanf("%d", &T);
for (int i = 1; i <= T; ++i)
{
memset(vis, 0, sizeof(vis));
scanf("%d%d", &p, &q);
vis[0][0] = 1;
steps[0] = 0;
printf("Scenario #%d:\n", i);
if (!dfs(0, 0, 1))
printf("impossible\n");
printf("\n");
}
}
C - Catch That Cow
三种走法,+1,-1,*2,枚举就可,如果初始时人已经比牛前最短的方式就是一直-1
#include<cstdio>
#include<queue>
int N, K;
bool vis[100005];
struct T
{
int x, step;
};
std::queue<T> q;
int main(void)
{
T t;
scanf("%d%d", &N, &K);
if (N < K)
{
q.push(T{ N,0 });
vis[N] = 1;
while (!q.empty())
{
t = q.front();
if (t.x + 1 <= 100000 && !vis[t.x + 1])
{
if (t.x + 1 == K)
{
printf("%d", t.step + 1);
break;
}
vis[t.x + 1] = 1;
q.push(T{ t.x + 1,t.step + 1 });
}
if (t.x - 1 >= 0 && !vis[t.x - 1])
{
if (t.x - 1 == K)
{
printf("%d", t.step + 1);
break;
}
vis[t.x - 1] = 1;
q.push(T{ t.x - 1 ,t.step + 1 });
}
if (t.x <= 50000 && !vis[t.x * 2])
{
if (t.x * 2 == K)
{
printf("%d", t.step + 1);
break;
}
vis[t.x * 2] = 1;
q.push(T{ t.x * 2 ,t.step + 1 });
}
q.pop();
}
}
else
printf("%d", N - K);
}
D - Pots
利用结构体种的f来记录父亲,每次bfs拥有填充1 填充2 清空1 清空2 1倒入2 2倒入1 6种操作,并且倒入操作时考虑是否容器能够装的下,如果杯中出现了需要的水的体积就递归倒序输出,另外如果出现a||b直接等于k时可以直接一步判定,在这之外如果a==b也可以直接判定不可能
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
int a, b, c;
bool vis[1000][1000];
struct T
{
int w[2], step, c, f;
}t, q[100010];
bool flag;
void P(int t)
{
if (q[t].f)
P(q[t].f);
switch (q[t].c)
{
case 0:
printf("FILL(1)\n");
break;
case 1:
printf("FILL(2)\n");
break;
case 2:
printf("DROP(1)\n");
break;
case 3:
printf("DROP(2)\n");
break;
case 4:
printf("POUR(2,1)\n");
break;
case 5:
printf("POUR(1,2)\n");
break;
}
}
int main(void)
{
while (~scanf("%d%d%d", &a, &b, &c))
{
flag = 0;
if (c == a)
printf("1\nFILL(1)\n");
else if (c == b)
printf("1\nFILL(2)\n");
else
{
if (a != b)
{
memset(vis, 0, sizeof(vis));
t.w[0] = t.w[1] = t.step = t.c = t.f = 0;
vis[0][0] = 1;
int r = 0, l = 0;
q[r++] = t;
while (l < r)
{
t = q[l];
if (!vis[a][t.w[1]])
{
vis[a][t.w[1]] = 1;
t.w[0] = a;
t.c = 0;
++t.step;
t.f = l;
q[r++] = t;
}
t = q[l];
if (!vis[t.w[0]][b])
{
vis[t.w[0]][b] = 1;
t.w[1] = b;
t.c = 1;
++t.step;
t.f = l;
q[r++] = t;
}
t = q[l];
if (!vis[0][t.w[1]])
{
vis[0][t.w[1]] = 1;
t.w[0] = 0;
t.c = 2;
++t.step;
t.f = l;
q[r++] = t;
}
t = q[l];
if (!vis[t.w[0]][0])
{
vis[t.w[0]][0] = 1;
t.w[1] = 0;
t.c = 3;
++t.step;
t.f = l;
q[r++] = t;
}
t = q[l];
if (t.w[0] + t.w[1] <= a)
{
if (!vis[t.w[0] + t.w[1]][0])
{
vis[t.w[0] + t.w[1]][0] = 1;
t.w[0] = t.w[0] + t.w[1];
t.w[1] = 0;
t.c = 4;
++t.step;
t.f = l;
q[r++] = t;
if (t.w[0] == c)
{
flag = 1;
printf("%d\n", t.step);
P(r - 1);
break;
}
}
}
else
{
if (!vis[a][t.w[0] + t.w[1] - a])
{
vis[a][t.w[0] + t.w[1] - a] = 1;
t.w[1] = t.w[0] + t.w[1] - a;
t.w[0] = a;
t.c = 4;
++t.step;
t.f = l;
q[r++] = t;
if (t.w[1] == c)
{
flag = 1;
printf("%d\n", t.step);
P(r - 1);
break;
}
}
}
t = q[l];
if (t.w[0] + t.w[1] <= b)
{
if (!vis[0][t.w[0] + t.w[1]])
{
vis[0][t.w[0] + t.w[1]] = 1;
t.w[1] = t.w[0] + t.w[1];
t.w[0] = 0;
t.c = 5;
++t.step;
t.f = l;
q[r++] = t;
if (t.w[1] == c)
{
flag = 1;
printf("%d\n", t.step);
P(r - 1);
break;
}
}
}
else
{
if (!vis[t.w[0] + t.w[1] - b][b])
{
vis[t.w[0] + t.w[1] - b][b] = 1;
t.w[0] = t.w[0] + t.w[1] - b;
t.w[1] = b;
t.c = 5;
++t.step;
t.f = l;
q[r++] = t;
if (t.w[0] == c)
{
flag = 1;
printf("%d\n", t.step);
P(r - 1);
break;
}
}
}
++l;
}
}
if (!flag)
printf("impossible\n");
}
}
}
E - 非常可乐
和D题解法一致,只是多了一个瓶子而已,枚举6种倒法,且不要求打印路径,这次学会用循环写而不是针对每个特殊情况去写代码,代码量少了很多,学习ING
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
int s[3];
bool vis[100][100][100];
struct T
{
int w[3], step;
}t, q[100010];
using namespace std;
bool flag;
void pour(int j, int& a, int& b)
{
int cnt = a + b;
b = min(cnt, s[j]);
a = cnt - b;
}
int main(void)
{
while (~scanf("%d%d%d", &s[0], &s[1], &s[2]) && s[0] + s[1] + s[2])
{
flag = 0;
if (s[0] & 01)
printf("NO\n");
else
{
flag = 0;
memset(vis, 0, sizeof(vis));
t.step = 0, t.w[0] = s[0], t.w[1] = t.w[2] = 0;
int l = 0, r = 0;
q[r++] = t;
while (l < r && !flag)
{
for (int i = 0; i < 3; ++i)
{
if (q[l].w[i] > 0)
for (int j = 0; j < 3; ++j)
{
if (i == j) continue;
t = q[l];
pour(j, t.w[i], t.w[j]);
if (!vis[t.w[0]][t.w[1]][t.w[2]])
{
vis[t.w[0]][t.w[1]][t.w[2]] = 1;
++t.step;
if (t.w[0] == s[0] / 2 && t.w[1] == s[0] / 2 || t.w[0] == s[0] / 2 && t.w[2] == s[0] / 2 || t.w[2] == s[0] / 2 && t.w[1] == s[0] / 2)
{
flag = 1;
printf("%d\n", t.step);
break;
}
q[r++] = t;
}
}
}
++l;
}
if (!flag)
printf("NO\n");
}
}
}
F - 马走日
和B题类似,甚至更简单,直接枚举就可
#include<cstdio>
#include<cstring>
int p, q;
int dir[8][2] = { -1,-2,1,-2,-2,-1,2,-1,-2,1,2,1,-1,2,1,2 };
bool vis[11][11];
int ans;
void dfs(int x, int y, int cnt)
{
if (cnt == p * q)
{
++ans;
return;
}
for (int i = 0; i < 8; ++i)
{
int tx = x + dir[i][0], ty = y + dir[i][1];
if (vis[tx][ty] || tx < 0 || ty < 0 || tx >= p || ty >= q)
continue;
vis[tx][ty] = 1;
dfs(tx, ty, cnt + 1);
vis[tx][ty] = 0;
}
return;
}
int main(void)
{
int T,a,b;
scanf("%d", &T);
for (int i = 1; i <= T; ++i)
{
ans = 0;
memset(vis, 0, sizeof(vis));
scanf("%d%d%d%d", &p, &q,&a,&b);
vis[a][b] = 1;
dfs(a, b, 1);
printf("%d\n", ans);
}
}
G - 棋盘问题
vis数组记录棋子占据的列,每次枚举从x行开始后的任意一行,如果放置的棋子数到达了k,则输出
#include<cstdio>
#include<cstring>
int n, k;
bool vis[10];
char map[10][10];
int ans;
void dfs(int x, int cnt)
{
if (cnt == k)
{
++ans;
return;
}
for (int i = x; i < n; ++i)
for (int j = 0; j < n; ++j)
{
if (map[i][j] == '#' && !vis[j])
{
vis[j] = 1;
dfs(i + 1, cnt + 1);
vis[j] = 0;
}
}
}
int main(void)
{
while (~scanf("%d%d", &n, &k) && n + k > 0)
{
ans = 0;
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; ++i)
scanf("%s", map[i]);
dfs(0, 0);
printf("%d\n", ans);
}
}
H - 拯救行动
和一般的迷宫区别不大,就是在结构体种定义一个wait的bool变量,如果遇到守卫,wait就变为true,每次bfs的时候先检测队首是否为wait,如果是的话就把wait改为false,增加步数,再放入队列即可
#include<cstdio>
#include<cstring>
#include<queue>
int m, n;
int dir[4][2] = { 0,1,1,0,0,-1,-1,0 };
bool vis[205][205];
char map[205][205];
struct T
{
int s, x, y;
bool w;
}t;
std::queue<T> q;
int main(void)
{
int T, sx, sy;
bool flag;
scanf("%d", &T);
getchar();
for (int i = 1; i <= T; ++i)
{
flag = 0;
sx = -1;
memset(vis, 0, sizeof(vis));
scanf("%d%d", &m, &n);
getchar();
for (int i = 0; i < m; ++i)
{
fgets(map[i], 205, stdin);
for(int j=0;map[i][j]&&sx==-1;++j)
if (map[i][j] == 'r')
{
sx = i, sy = j;
}
}
vis[sx][sy] = 1;
t.x = sx, t.y = sy, t.w = 0, t.s = 0;
q.push(t);
while (!q.empty()&&!flag)
{
t = q.front();
if (!t.w)
{
for (int i = 0; i < 4; ++i)
{
t = q.front();
int tx = t.x + dir[i][0], ty = t.y + dir[i][1];
if (tx < 0 || ty < 0 || tx >= m || ty >= n || vis[tx][ty] || map[tx][ty] == '#')
continue;
if (map[tx][ty] == 'a')
{
flag = 1;
printf("%d\n", t.s + 1);
break;
}
else if (map[tx][ty] == 'x')
{
vis[tx][ty] = 1;
t.x = tx, t.y = ty;
++t.s;
t.w = 1;
q.push(t);
}
else
{
vis[tx][ty] = 1;
t.x = tx, t.y = ty;
++t.s;
t.w = 0;
q.push(t);
}
}
}
else
{
t.w = 0;
++t.s;
q.push(t);
}
q.pop();
}
if (flag)
{
while (!q.empty())
q.pop();
}
else
printf("Impossible\n");
}
}
新加的I就是在难为我,(¬︿̫̿¬☆)