目录
②、将get的坐标全部赋值为-1(这样为被改变的就是到达不了的)
①方法一 扩大边界染色的范围,数组定义为1到n之间,从(0,0)(即边界外)开始染色,里面未染色的就是被包围的
五、P1596 [USACO10OCT] Lake Counting S
七、P2895 [USACO08FEB] Meteor Shower S
八、P1219 [USACO1.5] 八皇后 Checker Challenge
十、P1825 [USACO11OPEN] Corn Maze S
十一、P2036 [COCI 2008/2009 #2] PERKET
作业心得(前言)
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;
}