20200203DLUT寒假训练赛div2-简单搜索专场

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就是在难为我,(¬︿̫̿¬☆)

发布了8 篇原创文章 · 获赞 0 · 访问量 200

猜你喜欢

转载自blog.csdn.net/qq_45961715/article/details/104159214