搜索+基础数据结构作业

目录

作业心得(前言)

作业

一、P4387 【深基15.习9】验证栈序列​​​​​​

1、题目

2、思路

3.题解步骤

①创建三个数组(全局),在main之外创建,防止爆内存

②模拟入栈和栈顶弹出过程

③如果栈空(j==0),就说明有这种出栈顺序可能

3、完整代码

二、P1605 迷宫

1、题目

2、思路

3、解题步骤

①创建变量来存放迷宫和标记,还有用变量来放坐标移动的方向

②创建dfs函数

4、完整代码

三、P1443 马的遍历

1、题目

2、思路

3、解题步骤

①创建队列和变量

②、将get的坐标全部赋值为-1(这样为被改变的就是到达不了的)

③bfs

4、完整代码

四、P1162 填涂颜色

1、题目

2、思路

3、完整代码

①方法一 扩大边界染色的范围,数组定义为1到n之间,从(0,0)(即边界外)开始染色,里面未染色的就是被包围的

②方法二 沿着边界染色

五、P1596 [USACO10OCT] Lake Counting S

1、题目

2、思路

3、核心代码

4、完整代码

六、P2404 自然数的拆分问题

1、题目

2、思路

3、核心代码

4、完整代码

七、P2895 [USACO08FEB] Meteor Shower S

1、题目

2、思路

3、核心代码

4、完整代码

八、P1219 [USACO1.5] 八皇后 Checker Challenge

1、题目

2、思路

3、完整代码

九、P2392 kkksc03考前临时抱佛脚

1、题目

2、思路

3、完整代码

十、P1825 [USACO11OPEN] Corn Maze S

1、题目

2、思路

3、核心代码

4、完整代码

十一、P2036 [COCI 2008/2009 #2] PERKET

1、题目

2、思路

3、核心代码

4、完整代码


作业心得(前言)

1.dfs:深度优先搜索,从一个未访问的节点开始,沿着一条路一直走到底,直到走到这条尽头,返回上一节点,再从另一条路走到底······不断递归重复的过程,直到所有的节点被访问过。特点:不撞南墙不回头,走一条路,不行的话,换一条路。

2.bfs:广度优先搜索,从一个未访问过的节点出发,访问该节点相邻的节点,再访问相邻节点的相邻的节点,直到所以的点被访问。

3.对于搜索的题dfs和bfs两种方法的选择,一般用dfs求路径总和(方案总数),一般用bfs求最短路径(时间)。这只是一般规律,具体问题得具体来看,主要得理解题目意思,理清思路。

作业

一、P4387 【深基15.习9】验证栈序列​​​​​​

1、题目

2、思路

用三个数组来模拟栈序列,用一个数组来放入栈序列,一个数组来放出栈序列,一个数字模拟栈;

3.题解步骤

①创建三个数组(全局),在main之外创建,防止爆内存
int arr1[100010];//入栈序列
int arr2[100010];//出栈序列
int zhan[100010];//模拟栈
②模拟入栈和栈顶弹出过程
int j = 0;
int k = 0;
for (int i = 0; i < n; i++)
{
	//入栈
	j++;
	zhan[j] = arr1[i];
	while (j > 0 && zhan[j] == arr2[k])//出栈
	{
		j--;
		k++;
	}
}
③如果栈空(j==0),就说明有这种出栈顺序可能
if (j > 0)
{
	printf("No\n");
}
else
{
	printf("Yes\n");
}

3、完整代码

#include <stdio.h>
int arr1[100010];//入栈序列
int arr2[100010];//出栈序列
int zhan[100010];//模拟栈
int main()
{
	int q = 0;
	scanf("%d", &q);
	while (q--)
	{
		int n;
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &arr1[i]);
		}
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &arr2[i]);
		}
		int j = 0;
		int k = 0;
		for (int i = 0; i < n; i++)
		{
			//入栈
			j++;
			zhan[j] = arr1[i];
			while (j > 0 && zhan[j] == arr2[k])
			{
				j--;
				k++;
			}
		}
		if (j > 0)
		{
			printf("No\n");
		}
		else
		{
			printf("Yes\n");
		}
	}
	return 0;
}

二、P1605 迷宫

1、题目

2、思路

因为题目问的是有多少种方案,所以考虑用dfs ,用dfs的模板就可以

3、解题步骤

①创建变量来存放迷宫和标记,还有用变量来放坐标移动的方向
int a[10][10];//存放迷宫
int book[10][10];//用来标记
int fy, fx, n, m;
int sum = 0;//总方案数
int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
②创建dfs函数
void dfs(int x, int y)
{
	if (x == fx && y == fy)
	{
		sum++;
		return;
	}
	int tx, ty;
	for (int k = 0; k < 4; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
		if (1 <= tx && tx <= n && 1 <= ty && ty <= m && a[tx][ty] == 0 && book[tx][ty] == 0)//判断是否越界,是否有障碍物,是否走过
		{
			book[tx][ty] = 1;
			dfs(tx, ty);
			book[tx][ty] = 0;//需要回溯标记回去
		}
	}
	return;
}

4、完整代码

#include <stdio.h>
int a[10][10];//存放迷宫
int book[10][10];//用来标记
int fy, fx, n, m;
int sum = 0;//总方案数
int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
void dfs(int x, int y)
{
	if (x == fx && y == fy)
	{
		sum++;
		return;
	}
	int tx, ty;
	for (int k = 0; k < 4; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
		if (1 <= tx && tx <= n && 1 <= ty && ty <= m && a[tx][ty] == 0 && book[tx][ty] == 0)//判断是否越界,是否有障碍物,是否走过
		{
			book[tx][ty] = 1;
			dfs(tx, ty);
			book[tx][ty] = 0;//需要回溯标记回去
		}
	}
	return;
}
int main()
{
	int t;
	scanf("%d %d %d", &n, &m, &t);
	int sx, sy;
	scanf("%d %d %d %d", &sx, &sy, &fx, &fy);
	for (int i = 1; i <= t; i++)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		a[x][y] = 1;
	}
	book[sx][sy] = 1;
	dfs(sx, sy);
	printf("%d", sum);
	return 0;
}

三、P1443 马的遍历

1、题目

2、思路

因为题目问的马到达某个点最少要走几步,所以考虑用bfs求最短路径,需要特别注意的国际象棋的规则,马移动的方向有八个

3、解题步骤

①创建队列和变量
struct note
{
	int x;
	int y;
	int s;//记录当前步数
}que[160010];//队列
int next[8][2] = { {2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2 },{-1,2 },{-1,-2} };//主要是马走的方向有8个
int book[401][401] = {0};//记录没有走过的
int get[401][401];//存储对应坐标的最少步数
②、将get的坐标全部赋值为-1(这样为被改变的就是到达不了的)
for (int i = 1; i <= n; i++)
{
	for (int j = 1; j <= m; j++)
	{
		get[i][j] = -1;
	}
}
③bfs
	int head = 1;
	int tail = 1;
	que[tail].x = sx;
	que[tail].y = sy;
	que[tail].s = 0;
	tail++;//入队
	book[sx][sy] = 1;
	get[sx][sy] = 0;
	while (head < tail)
	{
		for (int k = 0; k < 8; k++)
		{
			tx = que[head].x + next[k][0];
			ty = que[head].y + next[k][1];
			if (tx<1 || tx>n || ty<1 || ty>m)
			{
				continue;
			}
			if (book[tx][ty] == 0)
			{
				book[tx][ty] = 1;
				que[tail].x = tx;
				que[tail].y = ty;
				que[tail].s = que[head].s + 1;
				get[tx][ty] = que[tail].s;//get[tx][ty]=get[que[head].x][que[head].y]+1,也可以这样来表示,直接在扩展之前的基础上加1
				tail++;
			}
		}
		head++;//继续扩展
	}

4、完整代码

#include <stdio.h>//因为是最少用几步到最后,所以考虑bfs,求最少步数,
struct note
{
	int x;
	int y;
	int s;//记录当前步数
}que[160010];
int next[8][2] = { {2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2 },{-1,2 },{-1,-2} };//主要是马走的方向有8个
int book[401][401] = {0};//记录没有走过的
int get[401][401];//存储对应坐标的最少步数
int main()
{
	int n, m, sx, sy, tx, ty;
	scanf("%d %d %d %d", &n, &m, &sx, &sy);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			get[i][j] = -1;
		}
	}
	int head = 1;
	int tail = 1;
	que[tail].x = sx;
	que[tail].y = sy;
	que[tail].s = 0;
	tail++;
	book[sx][sy] = 1;
	get[sx][sy] = 0;
	while (head < tail)
	{
		for (int k = 0; k < 8; k++)
		{
			tx = que[head].x + next[k][0];
			ty = que[head].y + next[k][1];
			if (tx<1 || tx>n || ty<1 || ty>m)
			{
				continue;
			}
			if (book[tx][ty] == 0)
			{
				book[tx][ty] = 1;
				que[tail].x = tx;
				que[tail].y = ty;
				que[tail].s = que[head].s + 1;
				get[tx][ty] = que[tail].s;//get[tx][ty]=get[que[head].x][que[head].y]+1,也可以这样来表示,直接在扩展之前的基础上加1
				tail++;
			}
		}
		head++;//继续扩展
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			printf("%-5d", get[i][j]);//注意打印格式
		}
		printf("\n");
	}
	return 0;
}

四、P1162 填涂颜色

1、题目

2、思路

将边界染色,用另一个数组b来存储数组a的值,把从开始边界未被包围0染色变成1;剩下的部分就是题目求的被包围的部分,打印的话,b为零的部分就打印2,其余就打印原本a数组的部分。

用dfs和bfs都可以 ,下面用dfs染色扩展了,将边界染色有两种方法,一种扩大边界染色的范围,另一种沿着边界遍历染色

3、完整代码

①方法一 扩大边界染色的范围,数组定义为1到n之间,从(0,0)(即边界外)开始染色,里面未染色的就是被包围的
#include <stdio.h>
int b[35][35] = { 0 };
int a[35][35];
int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
int n;
void dfs(int x, int y)
{
	b[x][y] = 1;
	int tx, ty;
	for (int k = 0; k < 4; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
		if (tx<0 || tx>n + 1 || ty<0 || ty>n + 1)//扩大结束的条件
		{
			continue;
		}
		if (b[tx][ty] == 0)
		{
			dfs(tx, ty);
		}
	}
	return;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			scanf("%d", &a[i][j]);
			b[i][j] = a[i][j];
		}
	}
	dfs(0, 0);//从(0,0)把边界染色,在1到n之外,确保可以染色
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (b[i][j] == 0)
			{
				printf("2 ");
			}
			else
			{
				printf("%d ", a[i][j]);
			}
		}
		printf("\n");
	}
	return 0;
}
②方法二 沿着边界染色
第二种沿着边界染色
#include <stdio.h>
int b[35][35] = { 0 };
int a[35][35];
int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
int n;
void dfs(int x, int y)
{
	if (x<1 || x>n || y<1 || y>n || b[x][y] != 0)
	{
		return;
	}
	b[x][y] = 1;
	int tx, ty;
	for (int k = 0; k < 4; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
		dfs(tx, ty);
	}
	return;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			scanf("%d", &a[i][j]);
			b[i][j] = a[i][j];
		}
	}
	for (int i = 1; i <= n; i++)//沿着边框搜索染色
	{
		if (b[i][1] == 0)
			dfs(i, 1);
		if (b[i][n] == 0)
			dfs(i, n);
		if (b[1][i] == 0)
			dfs(1, i);
		if (b[n][i] == 0)
			dfs(n, i);
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (b[i][j] == 0)
			{
				printf("2 ");
			}
			else
			{
				printf("%d ", a[i][j]);
			}
		}
		printf("\n");
	}
	return 0;
}

五、P1596 [USACO10OCT] Lake Counting S

1、题目

2、思路

可以就看成是啊哈算法上的染色问题,根据染不同的颜色得出岛屿的个数,同理也可以把水坑染成同一颜色,或者不同颜色来统计。

3、核心代码

	int sum = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)//遍历每一点
		{
			if (a[i][j] == 'W')//未被染色的
			{
				sum++;
				book[i][j] = 1;
				dfs(i, j,sum);//将不同的水坑染成不同的颜色,也可以同意染成一样的颜色,用sum来计数就可以
			}
		}
	}
void dfs(int x, int y,char color)
{
	int tx, ty;
	a[x][y] = color;
	for (int k = 0; k < 8; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
		if (tx<1 || tx>n || ty<1 || ty>m)//之前忘记从1到n 开始输入了
		{
			continue;
		}
		if (a[tx][ty] == 'W' && book[tx][ty] == 0)
		{
			book[tx][ty] = 1;
			dfs(tx, ty, color);
		}
	}
	return;
}

4、完整代码

#include <stdio.h>
char a[110][110];
int book[110][110] = { 0 };
int next[8][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,-1},{-1,1} };//一共8个方向
int n, m;
void dfs(int x, int y,char color)
{
	int tx, ty;
	a[x][y] = color;
	for (int k = 0; k < 8; k++)
	{
		tx = x + next[k][0];
		ty = y + next[k][1];
		if (tx<1 || tx>n || ty<1 || ty>m)//之前忘记从1到n 开始输入了
		{
			continue;
		}
		if (a[tx][ty] == 'W' && book[tx][ty] == 0)
		{
			book[tx][ty] = 1;
			dfs(tx, ty, color);
		}
	}
	return;
}
int main()
{
	scanf("%d %d", &n, &m);
	getchar();
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			scanf("%c", &a[i][j]);
		}
		getchar();//注意吸收换行
	}
	int sum = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (a[i][j] == 'W')
			{
				sum++;
				book[i][j] = 1;
				dfs(i, j,sum);//将不同的水坑染成不同的颜色,也可以同意染成一样的颜色,用sum来计数就可以
			}
		}
	}
	printf("%d\n", sum);
	return 0;
}

六、P2404 自然数的拆分问题

1、题目

2、思路

也是一道搜索的题目,用的是dfs,深搜,不过需要注意的是答案的顺序,是升序的。

设置这样的dfs(int a, int b, int step) a表示所选择起始的数,b表示加上数的和,step表示所选择的第step个数,当和b等于n时候,递归结束

3、核心代码

void dfs(int a, int b, int step)//a表示所选择起始的数,b表示加上数的和,step表示所选择的第step个数
{

	if (b == n)
	{
		for (int i = 0; i < step; i++)
		{
			if (i == 0)
			{
				printf("%d", arr[i]);
			}
			else
			{
				printf("+%d", arr[i]);
			}
		}
		printf("\n");
		return;
	}
	for (int i = a; i <= n - b; i++)//在之前所选择的基础上,i递增
	{
		if (i == n)//防止n单独被打印出来
		{
			continue;
		}
		arr[step] = i;
		//b += i;//这里可以改
		//dfs(i, b, step + 1);//因为打印的是递增的序列,这样不会重复打印,2,3  3,2;
		//b -= i;
		dfs(i,b+i,step+1);//这样回溯就是之前的和,注意传入的是i,不是a,在前一个基础上做选择
	}
	return;
}

4、完整代码

#include <stdio.h>
int arr[10];
int n;
void dfs(int a, int b, int step)//a表示所选择起始的数,b表示加上数的和,step表示所选择的第step个数
{

	if (b == n)
	{
		for (int i = 0; i < step; i++)
		{
			if (i == 0)
			{
				printf("%d", arr[i]);
			}
			else
			{
				printf("+%d", arr[i]);
			}
		}
		printf("\n");
		return;
	}
	for (int i = a; i <= n - b; i++)//在之前所选择的基础上,i递增
	{
		if (i == n)//防止n单独被打印出来
		{
			continue;
		}
		arr[step] = i;
		//b += i;//这里可以改
		//dfs(i, b, step + 1);//因为打印的是递增的序列,这样不会重复打印,2,3  3,2;
		//b -= i;
		dfs(i,b+i,step+1);//这样回溯就是之前的和
	}
	return;
}
int main()
{
	scanf("%d", &n);
	dfs(1, 0, 0);
	return 0;
}

七、P2895 [USACO08FEB] Meteor Shower S

1、题目

2、思路

因为求的最短时间,所以考虑用bfs ,用 int time[310][310];//对应坐标存放陨石砸坑的时间,只要人走过的时间比陨石砸的时间晚就可以走,直到走到安全位置为止。还有题目比较坑人的点,人走的坐标是可以超过300的

3、核心代码

	for (int i = 0; i < 310; i++)
	{
		for (int j = 0; j < 310; j++)
		{
			time[i][j] = -1;//时间全部初始化为-1,为-1的坐标说明是安全的
		}
	}

标记陨石砸落的时间及位置

	scanf("%d", &m);
	while (m--)
	{
		int x, y, t;
		scanf("%d %d %d", &x, &y, &t);
		for (int k = 0; k < 5; k++)//5个方向
		{
			tx = x + next[k][0];
			ty = y + next[k][1];
			if (tx >= 0 && ty >= 0 && (time[tx][ty] == -1 || t < time[tx][ty]))//没有超出第一象限,且 没有被砸过或者当前砸的时间小于被砸过的时间(取最先的时间)
			{
				time[tx][ty] = t;
			}
		}
	}

4、完整代码

#include <stdio.h>//注意题目可以人走的坐标可以超出300
struct note
{
	int x;
	int y;
	int t;
}que[90010];
int book[310][310] = { 0 };
int time[310][310];//对应坐标存放陨石砸坑的时间
int main()
{
	int next[5][2] = { {0,0},{0,1},{1,0},{0,-1},{-1,0} };也为了标记陨石四周
	int m, tx, ty;
	for (int i = 0; i < 310; i++)
	{
		for (int j = 0; j < 310; j++)
		{
			time[i][j] = -1;//时间全部初始化为-1;
		}
	}
	scanf("%d", &m);
	while (m--)
	{
		int x, y, t;
		scanf("%d %d %d", &x, &y, &t);
		for (int k = 0; k < 5; k++)//5个方向
		{
			tx = x + next[k][0];
			ty = y + next[k][1];
			if (tx >= 0 && ty >= 0 && (time[tx][ty] == -1 || t < time[tx][ty]))//没有超出第一象限,且 没有被砸过或者当前砸的时间小于被砸过的时间(取最先的时间)
			{
				time[tx][ty] = t;
			}
		}
	}
	int flag = 0;
	int head = 0;
	int tail = 0;
	que[tail].x = 0;
	que[tail].y = 0;
	que[tail].t = 0;
	tail++;
	book[0][0] = 1;
	while (head < tail)
	{
		if (time[que[head].x][que[head].y] == -1)//到达的该点是安全的,输出该点的时间即最小时间
		{
			printf("%d\n", que[head].t);
			flag = 1;
			break;
		}
		for (int k = 1; k <= 4; k++)
		{
			tx = que[head].x + next[k][0];
			ty = que[head].y + next[k][1];
			int ts = que[head].t + 1;//走到下一个位置的时间
			if (tx >= 0 && ty >= 0 && (ts < time[tx][ty] || time[tx][ty] == -1) && book[tx][ty] == 0)//到达的坐标的时间小于陨石砸坑的时间,就可以走该点,或者没有走过,也可以到达该点
			{
				book[tx][ty] = 1;
				que[tail].x = tx;
				que[tail].y = ty;
				que[tail].t = ts;
				tail++;
			}
		}
		head++;
	}
	if (flag == 0)//没有到达安全点
	{
		printf("-1\n");
	}
	return 0;
}

八、P1219 [USACO1.5] 八皇后 Checker Challenge

1、题目

2、思路

用一个数组存放来表示行数,依次存放不同的列数,用dfs来搜索,主要是对角线如何标记问题,这里要用到数学知识,从右上到左下的对角线有x+y为某一确定的值,从左上到右下的对角线满足x-y为某一确定的值,但是x-y的值可能为负数,不好标记,所以做了x-y+n的处理,因为x-y的最小值为1-n,加上n,最小值为1,确保是正数了,将整体向右偏移n个单位(坐标偏移不会影响我们需要达到的目的)。

3、完整代码

int a[15] = { 0 };//存放答案,行数,从第一行到n行放入对应的列数
int b[15] = { 0 };//标记列数
int c[30] = { 0 };//标记主对角线
int d[30] = { 0 };//标记副对角线
int sum = 0;
int n;
void dfs(int h)
{
	if (h == n + 1)//到h为n+1行结束
	{
		sum++;
		if (sum >= 4)
		{
			return;
		}
		for (int i = 1; i <= n; i++)
		{
			printf("%d ", a[i]);
		}
		printf("\n");
		return;
	}
	for (int i = 1; i <= n; i++)//列数
	{
		if (b[i] == 0 && c[h - i + n] == 0 && d[h + i] == 0)
		{
			b[i] = 1;
			c[h - i + n] = 1;
			d[h + i] = 1;
			a[h] = i;
			dfs(h + 1);
			b[i] = 0;
			c[h - i + n] = 0;
			d[h + i] = 0;
		}
	}
}
int main()
{
	scanf("%d", &n);
	dfs(1);//从第一行开始
	printf("%d\n", sum);
	return 0;
}

九、P2392 kkksc03考前临时抱佛脚

1、题目

2、思路

刚开始我想着是贪心算法或者dp之类的,又想着这是搜索作业,所以还是往dfs方向上想了,对于每一门学科,来模拟左脑和右脑的过程,dfs递归搜索,直到搜索的题目数大于该门的题目数递归结束 ,取左脑和右脑的最大值,因为只有两边脑子同时完成一门学科的作业才算完成。再取所有情况的最小值

3、完整代码

#include <stdio.h>
#include <limits.h>
int s[5];
int time[4][65];
int l, r;//模拟左脑和右脑
int minn;
int max(int a, int b)
{
	return a >= b ? a : b;
}
int min(int a, int b)
{
	return a <= b ? a : b;
}
void dfs(int x, int y)//列举所以可能
{
	if (x >= s[y])//当完成题目数超过,题目数就停止
	{
		minn = min(minn, max(r, l));//左脑和右脑全部完成题目才算完成,所以取最大值,然后与所有情况比较取最小值
		return;
	}
	l += time[y][x];//模拟左脑
	dfs(x + 1, y);
	l -= time[y][x];

	r += time[y][x];//模拟右脑
	dfs(x + 1, y);
	r -= time[y][x];
}
int main()
{
	int ans = 0;
	for (int i = 0; i < 4; i++)
	{
		scanf("%d", &s[i]);//输入四个题目数
	}
	for (int i = 0; i < 4; i++)//i门
	{
		for (int j = 0; j < s[i]; j++)//每个学科,对应的题目数量
		{
			scanf("%d", &time[i][j]);
		}
		r = 0;//重新清零
		l = 0;
		minn= INT_MAX;//记得每次取最大
		dfs(0, i);//第i门的第0小题
		ans += minn;//第i门做题目所花费的最少时间
	}
	printf("%d\n", ans);
	return 0;
}

十、P1825 [USACO11OPEN] Corn Maze S

1、题目

2、思路

因为题目要我们求的是最短时间,所以考虑bfs来求。也是bfs的模板,主要是关于传送点坐标转换的问题,可以遍历每数组每一个数看是否与本身相同,然后更新坐标,话不多说,先看核心代码

3、核心代码

		if (a[que[head].x][que[head].y] >= 'A' && a[que[head].x][que[head].y] <= 'Z')//是否为传送点
		{
			int f = 0;//这里需要用一个标记,才能完整结束
			for (int i = 1; i <= n; i++)
			{
				for (int j = 1; j <= m; j++)
				{
					if (a[que[head].x][que[head].y] == a[i][j] && (i != que[head].x || j != que[head].y))//一对传送点可能同一行或者同一列的,只有其中一个坐标不同就可以了;
					{
						que[head].x = i;//找到另外的传送点,更新坐标
						que[head].y = j;
						f = 1;
						break;
					}
				}
				if (f == 1)
				{
					break;
				}
			}
		}

4、完整代码

#include <stdio.h>
char a[310][310];
int book[310][310] = { 0 };
struct note
{
	int x;
	int y;
	int t;
}que[90010];
int main()
{
	int n, m, sx, sy, tx, ty;//sx,sy初始位置,p,q终点位置
	int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
	scanf("%d %d", &n, &m);
	getchar();
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			scanf("%c", &a[i][j]);
			if (a[i][j] == '@')
			{
				sx = i;
				sy = j;
			}
			
		}
		getchar();
	}
	int head = 1;
	int tail = 1;
	que[tail].x = sx;
	que[tail].y = sy;
	que[tail].t = 0;
	tail++;
	book[sx][sy] = 1;
	while (head < tail)
	{
		if (a[que[head].x][que[head].y]=='=')
		{
			printf("%d\n", que[head].t);
			break;
		}
		if (a[que[head].x][que[head].y] >= 'A' && a[que[head].x][que[head].y] <= 'Z')//传送
		{
			int f = 0;
			for (int i = 1; i <= n; i++)
			{
				for (int j = 1; j <= m; j++)
				{
					if (a[que[head].x][que[head].y] == a[i][j] && (i != que[head].x || j != que[head].y))//一对传送点可能同一行或者同一列的
					{
						que[head].x = i;//找到另外的传送点,更新坐标
						que[head].y = j;
						f = 1;
						break;
					}
				}
				if (f == 1)
				{
					break;
				}
			}
		}
		for (int k = 0; k < 4; k++)
		{
			tx = que[head].x + next[k][0];
			ty = que[head].y + next[k][1];
			if (tx<1 || tx>n || ty<1 || ty>m)
			{
				continue;
			}
			if (book[tx][ty] == 0 && a[tx][ty] != '#')
			{
				book[tx][ty] = 1;
				que[tail].x = tx;
				que[tail].y = ty;
				que[tail].t = que[head].t + 1;
				tail++;
			}
		}
		head++;
	}
	return 0;
}

十一、P2036 [COCI 2008/2009 #2] PERKET

1、题目

2、思路

求最小值,可以搜索所有可能取其中的最小值,即求总方案,用dfs搜索所有可能。先看核心代码。

3、核心代码

用min来取所有情况的最小值,j从0开始,表示所选择的菜的种类,当j>n时结束递归;用s和k记录酸度和苦度,每选择一种,酸度与苦度的差值绝对值与min比较

void dfs(int j)//当前选择的
{
	if (j >= n)
	{
		return;
	}
	for (int i = 0; i < n; i++)//模拟选择多种情况;选择不同的;
	{
		if (book[i] == 0)//没有选过
		{
			book[i] = 1;
			s *= arr[i][0];
			k += arr[i][1];
			if (abs(s - k) < min)
			{
				min = abs(s - k);
			}
			dfs(j + 1);
			s /= arr[i][0];
			k -= arr[i][1];
			book[i] = 0;
		}
	}
	return;
}

4、完整代码

#include <stdio.h>
#include <math.h>
#include <limits.h>
int n, s, k, min;
int arr[15][2];
int book[15] = { 0 };//标记食材
void dfs(int j)//当前选择的
{
	if (j >= n)
	{
		return;
	}
	for (int i = 0; i < n; i++)
	{
		if (book[i] == 0)
		{
			book[i] = 1;
			s *= arr[i][0];
			k += arr[i][1];
			if (abs(s - k) < min)
			{
				min = abs(s - k);
			}
			dfs(j + 1);
			s /= arr[i][0];
			k -= arr[i][1];
			book[i] = 0;
		}
	}
	return;
}
int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d %d", &arr[i][0], &arr[i][1]);//分别放入酸度和苦度
	}
	min = INT_MAX;
	s = 1;
	k = 0;
	dfs(0);
	printf("%d\n", min);
	return 0;
}

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

エース和

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值