第二周算法题思路总结

A - 5×5迷宫
定义一个二维数组:

int maze [5] [5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

思路:遇到迷宫问题,一般首先考虑dfs算法,因为在迷宫问题中,dfs的效率比较高一点.遇到最短路径等问题,一般使用bfs算法,在这道题一般选用的是bfs算法,也可以用dfs算法用栈将路径保存起来,这道题里限制了迷宫的大小
我自己的问题:起初没有理解清楚dfs算法的过程,以为尝试过的路径就是最短路径,殊不知需要使用栈来保存

在这里附上代码,我在这里,并没有构建栈,而是使用了栈的思想,利用数组来进行栈的模拟

//在这里我的思路是深度优先算法
#include<stdio.h>
int a[10][10],b[10][10];//在这里a数组是输入迷宫的路径,b数组是标记走过的路
int top,t=25;//top是栈顶,t表示5X5的所有可能,也可以理解为栈的大小
int min=99999999;//计算最小路径,用来控制输出,
int x1[50],y2[50];//保存所有尝试过的路径
int x2[50],y3[50];//保存最短路径
//在这里n,m表示迷宫的行和列,p,q表示的是终点坐标
int dfs(int x,int y,int step)
{
    int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//因为是迷宫问题,由四个方向,分别标记为向上走,向右走,向下走,向左右
    int tx,ty,k,q=0;
        if( x==4 && y==4 )//到达终点
     {
         if(top-1<t)
     for(k=0;k<top;k++)
   {
      x2[k]=x1[k];
      y3[k]=y2[k];
      t=top-1;
    }
        if(step<min)更新最短路径
            min=step;
        return 1;//这个return 是必须的,不然系统就会无法终结一直运行
    }
            for(k=0;k<=3;k++)
      {
        tx=x+next[k][0];//表示走的路径的x坐标
        ty=y+next[k][1];//y坐标
        if(tx <0 || tx>4 || ty>4 || ty<0)//边界,不能超出范围
            continue;
        if( a[tx][ty]==0 && b[tx][ty]==0)
        {   
            x1[top]=tx;
            y2[top]=ty;
            top++;
            b[tx][ty]=1;//标记这个点已经走过
           if( dfs(tx,ty,step+1))
                q=1;
               b[tx][ty]=0;//尝试结束后回溯
               top--;
        }
      }
    return q;
}
int main()
{
    int i,j;
    for(i=0;i<=4;i++)
        for(j=0;j<=4;j++)
            scanf("%d",&a[i][j]);//在这里输入迷宫
    b[0][0]=1;//标记已经走过
    dfs(0,0,0);//因为题目中给出了起点即为0,0
   if(a[0][0]==0)//判断起点是不是零
    printf("(%d, %d) \n",0,0);

    for(i=0;i<min;i++)//输出最短路径
    {
        printf("(%d, %d) \n",x2[i],y3[i]);
    }
        return 0;
}

B - 闪现!

Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.
If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?

Input
Line 1: Two space-separated integers: N and K
Output
Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
Sample Input

5 17

Sample Output

4

Hint
The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.

思路:首先应该使用哪种算法,求最短一般使用bfs(即广度优先算法),首先搞清除情况有几种,按照题目给的话,有三种情况,一种是x+1,基于5必须小于17的情况,一种是2x,但是2x的前提下 5 必须要小于 17 ,另外一种是x-1,必须是 a大于b的情况

扫描二维码关注公众号,回复: 2565862 查看本文章

以下是代码

//求最短时间,BFS算法
//有三种情况分别为x-1,x+1,2x
//如果a小于b这个值的话则会执行两种情况x+1,2x来进行判断
//a大于b这个值的话会执行一种情况a-b
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node
{
   int x;
   int y;
}node;//在这里我使用的队列这个概念
node a[105000];//防止溢出
int book[200000];//用book数组来标记有没有访问这个地方,以防止多次进行访问
int head,tail;//队列的头和尾
void bfs(int c,int b)
{
       if(b==c)///emmmmmm,如果起点与终点是同一位置的话不用移动
       {
         printf("0\n");
         return ;
       }
       if(b<c)//emmm在这里无法实行位移操作
       {
           printf("%d\n",c-b);
           return ;
       }
       head=1;
       tail=1;///初始化队列,保留第一位
       a[tail].x=0;//将time时间初始化
       a[tail++].y=c;//输入终点并且入队,所以tail的值会增加
       book[c]=1;//标记这个点走没走过
       //将每个队列的首进行三次扩展,扩展完毕即出队
       while(head<tail)//队列的头必须小于尾巴
       {
           if(a[head].y>1 && book[a[head].y-1]==0)
           {
               a[tail].x=a[head].x+1;//time加一
              a[tail++].y=a[head].y-1;//在队列最后减去1,并且tail加一入队
             book[a[head].y-1]=1;
           }
           if(a[head].y<100000 && book[a[head].y+1]==0)//为了位一后加1
           {
              a[tail].x=a[head].x+1;
              a[tail++].y=a[head].y+1;
              book[a[head].y+1]=1;
           }
           if(a[head].y<50000 && book[a[head].y*2]==0)
           {
              a[tail].x=a[head].x+1;
              a[tail++].y=a[head].y*2;
              book[2*a[head].y]=1;
           }
           if(a[head].y+1==b || a[head].y-1==b || a[head].y*2==b)
           {
              printf("%d\n",a[head].x+1); 

               break;
           }
           head++;//出队,这三种情况每轮一次就要有一个出队
       }

}
int main(void)
{
    int a;
    int b;
    while(scanf("%d %d",&a,&b)!=EOF)
    {
         memset(book,0,sizeof(book));//每次输入的时候需要把book数组清空,不然会影响到计算
         bfs(a,b);
    }
    return 0;

C - 不规则的棋盘

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
Sample Input

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1

Sample Output

2

思路:这道题的思路很简单,类似与八皇后问题,唯一需要注意的是,棋子是相同的,所以1 2 和 2 1是一样的,把这种情况排除,剩下的使用dfs算法即可

//类似与八皇后问题,应该使用dfs算法进行遍历
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
char chess[10][10];
int chess1[10];//在这里只需要对每一列进行判断
int sum,a,cnt=0,b;
void dfs(int s)
{
       int i;
       if(cnt==b)//如果所有棋子已经全部放置,在总数加1
       {
           sum++;
           return;//返回上层
       }
       else{
           if(s>=a)//越界
           return ;
           else
           {
               for(i=0;i<a;i++)//尝试把棋子放入//对每一列进行判断就好
               {
                   if((chess[s][i])=='#'&&(!chess1[i]))
                   {
                       chess1[i]=1;
                       cnt++;
                       dfs(s+1);
                       cnt--;
                       chess1[i]=0;
                   }
                }

             }
            dfs(s+1);//最后一列
         }
}
int main()
{
    int j;
    while(scanf("%d %d",&a,&b)&&(a!=-1)&&(b!=-1))
    { 
        memset(chess,0,sizeof(chess));
        memset(chess1,0,sizeof(chess1));
        for(j=0;j<a;j++)
         scanf("%s",chess[j]);
         sum=cnt=0;
         dfs(0);
         printf("%d\n",sum);
    }
    return 0;
}

D - 二进制?

Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.
Input
The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.
Output
For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.
Sample Input

2
6
19
0

Sample Output

10
100100100100100100
111111111111111111

思路:看查例子,发现数据十分大,肯定要考虑溢出情况,根据题目可看,首位必须为1,每一位只能是1或者0,所以有两种情况,乘10或者乘10+1,应用dfs算法进行搜索

//这个题依然使用深度搜索来进行
//因为每个数字都必须为1或者0
//所以有两种遍历的方式
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int f;
void dfs(  unsigned long long int  x,int k,int n)
{
        if(f)
            return ;
         if(x%n==0)
         {
             printf("%llu\n",x);
             f=1;
             return ;
         }
         if(k==19)//在这里应该考虑x的范围,如果超范围的话会溢出输出错误数据
             return ;
         dfs(x*10,k+1,n);//因为它必须为1或者0
         dfs(x*10+1,k+1,n);
}
int main()
{
    int n;
    while(scanf("%d",&n)&&n)
    {
        f=0;
        dfs(1,0,n);
    }
}

E - 喝可乐!
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出”NO”。
Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以”0 0 0”结束。
Output
如果能平分的话请输出最少要倒的次数,否则输出”NO”。
Sample Input

7 4 3
4 1 3
0 0 0

Sample Output

NO
3

思路:首先奇数不能平分排除掉,其次考虑有六种情况,每个杯子向其他两个杯子倒水,可以使用bfs算法或者数论解题

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int book[1000][1000];
int M, N, S;
int step = 0;
struct node
{
    int x;
    int y;
    int z;
    int l;
};
struct node a[105000];
void bfs()
{

    if (S % 2 != 0)
    {
        printf("NO\n");
        return;
    }
    if (M == N)
    {
        printf("1\n");
        return;
    }
    int head, tail, flag = 0;
    head = 1;
    tail = 1;
    a[tail].x = S;
    a[tail].y = 0;
    a[tail].z = 0;
    a[tail].l = 0;
   book[0][0] = 1;
    int sum = 0, j = 0;
    tail++;
    while (head != tail)
    {
           if ((a[head].x==a[head].y)&&a[head].y==S/2)
            {
              printf("%d\n", a[head].l);
              flag = 1;
              return;
            }
        for (j = 0; j < 6; j++) //不能自己给自己倒水
        {
            if (j == 0) //s->M
            {
                if (a[head].x == 0 || a[head].y == M)
                    continue;
                sum = a[head].x + a[head].y;
                a[tail].l = a[head].l + 1;
                a[tail].x = sum > M ? (sum - M) : 0;
                a[tail].y = sum > M ? M : sum;
                a[tail].z = a[head].z;


            }
            if (j == 1) //s->N
            {
                if (a[head].x == 0 || a[head].z == N)
                    continue;
                sum = a[head].x + a[head].z;
                a[tail].l = a[head].l + 1;
                a[tail].x = sum > N ? (sum - N) : 0;
                a[tail].z = sum > N ? N : sum;
                a[tail].y = a[head].y;


            }
            if (j == 2) //M->S
            {
                if (a[head].y == 0 || a[head].x == S)
                    continue;
                a[tail].x = a[head].x + a[head].y;
                a[tail].l = a[head].l + 1;
                a[tail].y = 0;
                a[tail].z = a[head].z;

            }
            if (j == 3) //headM->N
            {
                if (a[head].y == 0 || a[head].z == N)
                    continue;
                sum = a[head].y + a[head].z;
                a[tail].l = a[head].l + 1;
                a[tail].z = sum < N ? sum : N;
                a[tail].y = sum < N ? 0 : (sum - N);
                a[tail].x = a[head].x;

            }
            if (j == 4) //N->S
            {
              if (a[head].z == 0 || a[head].x == S)
                    continue;
                a[tail].z = 0;
                a[tail].l = a[head].l + 1;
                a[tail].x = a[head].z + a[head].x;
                a[tail].y = a[head].y;

            }
            if (j == 5) //N->M
            {

                if (a[head].z == 0 || a[head].y == M)
                {
                    continue;
                }
                a[tail].z = 0;
                a[tail].l = a[head].l + 1;
                a[tail].y = a[head].y + a[head].z;
                a[tail].x = a[head].x;
            }
             if (!book[a[tail].y][a[tail].z]) 
            {
                book[a[tail].y][a[tail].z] = 1;//tail放在其后
                tail++;
            }
        }
           head++;

    }
  if (flag == 0)
    printf("NO\n");
    return;
}
int main()
{
    int t;
    while (scanf("%d %d %d", &S, &M, &N) && S && M && N)
    {
        t = 0;
        if (N > M)
        {
            t = M;
            M = N;
            N = t;
        }
        step = 0;
        memset(book, 0, sizeof(book));
        memset(a, 0, sizeof(a));
        bfs();

    }
    return 0;
}

F - 勘探石油

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.
Input
The input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.
Output
For each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.
Sample Input

1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5 
****@
*@@*@
*@**@
@@@*@
@@**@
0 0 

Sample Output

0
1
2
2

思路:这道题使用dfs算法可解,求方法数一般使用dfs算法,本题需要考虑石油的四周如果有石油的话,勘测机的数量不加1

//这道题的思路就是通过dfs算法,来遍历石油的上下左右,有没有相同的
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char a[105][105];
int  b[105][105];
int M,N,sum=0;//采矿机的数量
void dfs(int i,int j)//将他的四周进行遍历
{
       if ((a[i][j] != '@')||b[i][j]==1) //越界和非石油的地方3 5
        return;
    b[i][j]=1;
      dfs(i-1,j-1);
    dfs(i-1,j);
    dfs(i-1,j+1);
    dfs(i,j-1);
    dfs(i,j+1);
    dfs(i+1,j-1);
    dfs(i+1,j);
    dfs(i+1,j+1);
}
int main()
{
    int i,j;
    scanf("%d %d",&M,&N);
    while((M!=0)&&(N!=0))
    {
        memset(b,0,sizeof(b));
        memset(a,0,sizeof(a));
        getchar();
       for(i=1;i<=M;i++)
        {
             for(j=1;j<=N;j++)
         {
             scanf("%c",&a[i][j]);
         }
         getchar();
        }
         sum=0;
         for(i=1;i<=M;i++)
          for(j=1;j<=N;j++)
          {
              if(a[i][j]=='@'&&b[i][j]==0)
              {
                dfs(i,j);
                sum++;
               }
          }
          printf("%d\n",sum);
       scanf("%d %d",&M,&N);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dream0130__/article/details/81411885