ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C语言程序设计100例之(63):红与黑

2022-02-03 19:35:19  阅读:209  来源: 互联网

标签:map return 瓷砖 int C语言 vis 63 棋子 100


例63   红与黑

问题描述

有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

输入

包括多个数据集合。每个数据集合的第一行是两个整数W和H,分别表示x方向和y方向瓷砖的数量。W和H都不超过20。在接下来的H行中,每行包括W个字符。每个字符表示一块瓷砖的颜色,规则如下

1)‘.’:黑色的瓷砖;

2)‘#’:白色的瓷砖;

3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。

当在一行中读入的是两个零时,表示输入结束。

输出

对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。

输入样例

6 9

....#.

.....#

......

......

......

......

......

#@...#

.#..#.

0 0

输出样例

45

        (1)编程思路。

        设函数f(x, y)计算从点(x,y)出发能够走过的黑瓷砖总数,则

        f(x, y) = 1 + f(x - 1, y) + f(x + 1, y) + f(x, y - 1) + f(x, y + 1)

        若点(x,y)超过了房子的范围(x < 0 || x >= w || y < 0 || y >= h)或该处为白色瓷砖,则f(x, y)的返回值为0。

        编写简单的递归函数即可。在函数中凡是走过的黑色瓷砖不能够被重复走过。可以通过每走过一块瓷砖就将它作标记的方法(最简单的方法是将其标记为白色瓷砖)保证不重复计算任何黑色瓷砖。

(2)源程序。

#include <stdio.h>

int w,h;

char map[21][21];

int f(int x, int y)

{

    if(x < 0 || x >= w || y < 0 || y >= h)   // 如果走出房子范围

       return 0;

    if(map[x][y] == '#')

       return 0;

    map[x][y] = '#';                 // 将走过的瓷砖做标记

    return 1 + f(x-1, y)+f(x+1,y)+f(x,y-1)+f(x,y+1);

}

int main()

{

    int i, j;

    while(scanf("%d %d", &h, &w) && w!=0 && h!=0)

    {

       for (i = 0; i < w; i++)

          scanf("%s", map[i]);

       for (i = 0; i < w; i++)

          for(j = 0; j < h; j++)

             if (map[i][j]=='@') printf("%d\n", f(i,j));

    }

    return 0;

}

习题63

63-1 马走日

问题描述

马在中国象棋以日字形规则移动。

请编写一段程序,给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

输入

第一行为整数T(T < 10),表示测试数据组数。

每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标n,m,x,y。(0<=x<=n-1,0<=y<=m-1, m < 10, n < 10)

输出

每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,0为无法遍历一次。

输入样例

1

5 4 0 0

输出样例

32

        (1)编程思路。

        马走日可以从一个位置跳到其他的8个位置,编写函数void dfs(int x,int y,int step),三个参数的含义是马第step步走到了位置(x,y)处。

        在函数中,若马走到的8个位置之一(tx,ty)在棋盘中并且没有走过(vis[tx][ty]为初始值0),则马走到该位置,即递归调用dfs(tx,ty,step+1)。

        若step==n*m,表示棋盘所有的位置都走过,计数cnt++。cnt定义为全局变量,初始值设为0。

       (2)源程序。

#include <stdio.h>

#include <string.h>

int cnt=0;

int vis[11][11]={0};

int n,m;

int dx[8]={-1,1,-2,2,-2,2,-1,1},dy[8]={-2,-2,-1,-1,1,1,2,2};

void dfs(int x,int y,int step)

{

    if (step==n*m)

    {

        cnt++;

        return;

    }

    int i;

    for (i=0;i<8;i++)

    {

        int tx=x+dx[i];

        int ty=y+dy[i];

        if (tx<0 || tx>=n || ty<0 || ty>=m || vis[tx][ty]==1)

            continue;

        vis[tx][ty]=1;

        dfs(tx,ty,step+1);

        vis[tx][ty]=0;

    }

}

int main()

{

    int t;

    scanf("%d",&t);

    while (t--)

    {

        memset(vis,0,sizeof(vis));

        cnt=0;

        int x,y;

        scanf("%d%d%d%d",&n,&m,&x,&y);

        vis[x][y]=1;

        dfs(x,y,1);

        printf("%d\n",cnt);

    }

    return 0;

}

63-2  城堡问题

问题描述

 

图1是一个城堡的地形图,其中符号“#”表示墙,“|”和“-”表示没有墙。

请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成m×n(m≤50,n≤50)个方块,每个方块可以有0~4面墙。

输入

输入第一行是两个整数n和m,分别是南北向、东西向的方块数。在接下来的n行里,每行有m个整数,一个整数表示一个方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。例如,方块(1,1)的数字11表示该方块周围有1堵西墙,1堵北墙和1堵南墙,即1+2+8=11。城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。输入的数据保证城堡至少有两个房间。

输出

城堡的房间数、城堡中最大房间所包括的方块数。

输入样例

4 7

11 6 11 6 3 10 6

7 9 6 13 5 15 5

1 10 12 7 13 7 5

13 11 10 8 10 12 13

输出样例

5

9

        (1)编程思路。

        表示方块周围墙的数字对应二进制数的低4位,每位表示一堵墙。最低位为1(设为第0位),表示西边有墙;第1位为1,表示北边有墙;第2位为1,表示东边有墙;第3位为1,表示南边有墙。可以简单用该数字分别与1、2、4、8进行按位与运算,若运算结果为0,则表示对应位置没有墙。某方向没有墙就可以继续向该方向走,同时方块数加1。

        编写简单的递归函数void dfs(int i,int j)求解以位置(i,j)出发的连通块中方块的个数。

      (2)源程序。

#include <stdio.h>

int map[51][51],vis[51][51]={0};

int area;

void dfs(int i,int j)

{

       if (vis[i][j]) return ;

       vis[i][j]=1;

       area++;

       if ((map[i][j]&1)==0) dfs(i,j-1);   // 西边没有墙,向西走

       if ((map[i][j]&2)==0) dfs(i-1,j);   // 北边没有墙,向北走

       if ((map[i][j]&4)==0) dfs(i,j+1);  // 东边没有墙,向东走

       if ((map[i][j]&8)==0) dfs(i+1,j);  // 南边没有墙,向南走

}

int main()

{

        int n,m;

       scanf("%d%d",&n,&m);

       int i,j;

       for (i=1;i<=n;i++)

         for (j=1;j<=m;j++)

            scanf("%d",&map[i][j]);

       int sum=0,maxArea=0;

       for (i=1;i<=n;i++)

         for (j=1;j<=m;j++)

         {

              if(!vis[i][j])

              {

                     sum++;

                     area=0;

                     dfs(i,j);

                     if (maxArea<area) maxArea=area;

              }

         }

       printf("%d\n%d\n",sum,maxArea);

       return 0;

}

63-3  棋盘问题

问题描述

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

输入

输入含有多组测试数据。

每组数据的第一行是两个正整数,n k(n <= 8 ,k <= n),用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。

当为-1 -1时表示输入结束。

随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

输出

对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

输入样例

2 1

#.

.#

4 4

...#

..#.

.#..

#...

-1 -1

输出样例

2

1

         (1)编程思路。

        编写递归函数void DFS(int row,int num)进行逐行搜索,row为当前搜索行,num为已填充的棋子数。

        定义数组int vis[10]用于标某一列上是否有棋子,因为每次递归下一行,所以每一行不会有冲突,只需判断这一列上是否有其他棋子。

        在第row行放棋子时,在该行找到一列j,如果row行j列没被标记放过棋子(vis[j]==0)且位置在棋盘内(map[i][j]=='#'),那么在该列放上棋子,并标记,即vis[j]=1;之后递归搜索下一行放下一个棋子,调用函数DFS(row+1,num+1)。

        若棋子已经用完(num>=k),则记录方案数加1,然后直接返回。

       (2)源程序1。

#include<stdio.h>

int vis[10];

char map[10][10];

int ans,k,n;  // ans表示方案数,k表示棋子数目,n表示棋盘的大小

void DFS(int row,int num) 

{

    if(num>=k)

    {

        ans++;

        return;

    }

    int i,j;

    for (i=row;i<n;i++)

    {

        for (j=0;j<n;j++)

        {

            if (!vis[j] && map[i][j]=='#')

            {

                vis[j]=1;  

                DFS(i+1,num+1);

                vis[j]=0; 

            }

        }

    }

}

int main()

{

       int i;

    while (scanf("%d%d",&n,&k))

    {

         if (n==-1&&k==-1)

            break;

         for (i=0;i<n;i++)

                     vis[i]=0;

         for (i=0;i<n;i++)

            scanf("%s",map[i]);

        ans=0;

        DFS(0,0);

        printf("%d\n",ans);

    }

    return 0;

}

        实际上,每行在放棋子的过程中,要么在该行找一个可行的列放一个棋子,要么在该行不放棋子。按这一思路,可以编写如下的程序。

       (3)源程序2。

#include<stdio.h>

int vis[10];

char map[10][10];

int ans,k,n;

void DFS(int row,int num)

{

    if(num==k)

    {

        ans++;

        return;

    }

    if (row>=n) return ;

    int j;

    for (j=0;j<n;j++)   // 当前行放一个棋子

    {

         if(!vis[j] && map[row][j]=='#')

         {

             vis[j]=1;

             DFS(row+1,num+1);

             vis[j]=0;

         }

    }

    DFS(row+1,num);      // 当前行不放棋子

}

int main()

{

    int i;

    while (scanf("%d%d",&n,&k))

    {

        if (n==-1&&k==-1)

            break;

        for (i=0;i<n;i++)

                     vis[i]=0;

        for (i=0;i<n;i++)

            scanf("%s",map[i]);

        ans=0;

        DFS(0,0);

        printf("%d\n",ans);

    }

    return 0;

}

标签:map,return,瓷砖,int,C语言,vis,63,棋子,100
来源: https://www.cnblogs.com/cs-whut/p/15861855.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有