UVa 657 掷骰子

意甲冠军:有一个大图。每个像素是格孩子只可能是 . * X 三种。代表背景、玻色子、色子点。

两格子是邻近或在通信,当且仅当两个格儿子*要么X。且具有共同的边,这是上下左右四个方向,斜过,即四连块。

个色子。将这个连通块中的X的连通块个数看做该色子的点数。

思路:两次深搜。第一次是由*和X来深搜每一个连通块。在深搜每一个连通块时由X来深搜X的连通块个数。这里能够通过两个标记数组visit来表示是否訪问过,visitx来表示是否訪问深搜X过。(也能够将X改为*、*改为.的方式实现,不用标记数组。之前我想的是用一个标记数组,然后对其值的推断来实现,不如两个标记数组来得简便和直观)

注意:在主函数的两个for循环进行深搜前。注意推断是否已訪问过,否则产生大量点数为0的色子。另外,由于这个循环每次成功去深搜都是深搜了一个大的连通块,所以色子个数的添加应该在这个循环里,不要放在dfs里~

(之前的思路是。深搜一次。*在深搜时遇到X则点数加1,X深搜时遇到X则点数不加。

发现对2行2列的数据*XXX就会出错。由于这样算一个,那个思路算出来的是两个。

之后看了网上的思路,參考了一下。两次深搜,学习了~)

这里的深搜都是标记其被訪问过,每次深搜都是标记完一个连通块。

然后统计了訪问的次数,即连通块的个数:色子数、色子的点数。(包含之前油田那题的深搜也是这样。)

inclusive 包括的,exclusive才是排他的~

这里通过用字符 . 来初始化图G,并从1而不是0開始,即在图外围围了一圈字符 . ,这样就可避免推断坐标是否出界。(加一圈外围的停止字符,避免推断坐标是否出界)

Code:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 55

int cmp_int(const void *_a, const void *_b);
void dfs(int hs,int ls);
void dfsx(int hs,int ls);

int w,h;
char G[MAXN][MAXN];
int visit[MAXN][MAXN];
int visitx[MAXN][MAXN];
int dir[][4]={{-1,1,0,0},{0,0,1,-1}};//LRDU。前x后y,前水平后竖直
int num[MAXN*MAXN];//对应色子的点数
int cnt;//色子个数 

int main()
{
 //freopen("657.in","r",stdin);
 //freopen("657.out","w",stdout);
 int thrw=1;
 while(scanf("%d%d",&w,&h) && w && h)
 {
  memset(G,'.',sizeof(G));
  memset(visit,0,sizeof(visit));
  memset(visitx,0,sizeof(visitx));
  for(int i=1;i<=h;++i)
  {
   getchar();
   for(int j=1;j<=w;++j)
   {
    G[i][j]=getchar();
   }
  }
  cnt=0;
  memset(num,0,sizeof(num));
  for(int i=1;i<=h;++i)
   for(int j=1;j<=w;++j)
    if(G[i][j]!='.' && !visit[i][j])//注意这里的!visit条件。不然会打出非常多点数为0的色子
    {
     dfs(i,j);
     cnt++;//色子数添加            //注意这个别放在dfs语句中了,想一想就理解了
     //printf("%d %d\n",i,j);
    }
  qsort(num,cnt,sizeof(num[0]),cmp_int);
  printf("Throw %d\n",thrw++);
  for(int i=0;i<cnt;++i)
   if(i==0) printf("%d",num[i]);
   else printf(" %d",num[i]);
  printf("\n\n");
 }
 return 0;
}

int cmp_int(const void *_a, const void *_b)
{
 return *(int*)_a-*(int*)_b;
}

void dfsx(int hs,int ls)
{//由X来遍历连通块
 if(G[hs][ls]!='X' || visitx[hs][ls]) return ;
 visitx[hs][ls]=1;
 for(int i=0;i<4;++i)
 {
  int nh=hs+dir[1][i];
  int nl=ls+dir[0][i];
  dfsx(nh,nl);
 }
}

void dfs(int hs,int ls)
{//从一点出发,由*和X来遍历连通块
 if(G[hs][ls]=='.' || visit[hs][ls]) return ;
 visit[hs][ls]=1;
 if(G[hs][ls]=='X' && !visitx[hs][ls])
 {
  dfsx(hs,ls);
  num[cnt]++;//点数添加
 }
 //else if(G[hs][ls]=='*')            //注意这里别加这个推断条件。由于就算是字符X也须要进行以下这个循环的遍历
  for(int i=0;i<4;++i)
  {
   int nh=hs+dir[1][i];
   int nl=ls+dir[0][i];
   dfs(nh,nl);
  }
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-08-30 06:45:55

UVa 657 掷骰子的相关文章

UVa 657 掷色子

题意:就是有一张大图,每个像素即格子只可能是 . * X 三种,分别代表背景.色子.色子的点数.两个格子是相邻的或连通的,当且仅当两个格子是*或X,且有公共边,即上下左右四个方向,对角不算,即四连块.将一个连通块看做一个色子,将这个连通块中的X的连通块个数看做该色子的点数. 思路:两次深搜.第一次是由*和X来深搜每个连通块,在深搜每个连通块时由X来深搜X的连通块个数.这里可以通过两个标记数组visit来表示是否访问过,visitx来表示是否访问深搜X过.(也可以将X改为*.*改为.的方式实现,不

华为历年试题(掷骰子游戏 7)

问题描述: 在掷骰子游戏中,会根据所掷数字在地图中前进几步,前进完成后需要根据当前地图位置所示的障碍进行相应操作,其中障碍表示: 1)  9:无障碍 2)  1:停掷一轮,即下轮所掷数字无效: 3)  2:后退两步,如果已经到起点不再后退: 4)  3:奖励前进一步 如果在游戏过程中,已经走到地图终点,则游戏结束.根据输入的地图数组,和5个骰子数的数组,返回最终玩家前进了多少步. 要求实现函数: void dice(int map_len, int* map, int* dice_val, in

模拟算法_掷骰子游戏&amp;&amp;猜数游戏

模拟算法是用随机函数来模拟自然界中发生的不可预测的情况,C语言中是用srand()和rand()函数来生成随机数. 先来介绍一下随机数的生成: 1.产生不定范围的随机数 函数原型:int rand() 产生一个介于0~RAD_MAX间的整数,其具体值与系统有关系.Linux下为2147483647.我们可以在include文件夹中的stdlib.h中可以看到(Linux在usr目录下,Windows在安装目录下) 1 #include<stdio.h> 2 #include<stdlib

第21本:《上帝掷骰子吗?》

第21本:<上帝掷骰子吗?> 这是一本关于量子论的科普读物,不过作者曹天元把一系列人物和实验用一种小说的形式讲 述了下来,很感叹作者深厚的理论知识和文字功底.这本书在豆瓣上评分在9.3-9.4,我的GTD阅读清单是按照评分顺序来整理的,超过9分的读物如果不 优先阅读真有点对不起书名里的上帝. 这类书既然是科普知识类的书,就很难找到可以执行的行动,这些知识体系能让你的视野开阔,当思考一个问题时不能被其表面现象所迷惑,任何一个定律都 不是绝对适用的.在读到能量不是连续的,而是一份一份的,再想到计算

骑士飞行棋第一版(掷骰子方法分开)

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 骑士飞行棋 8 { 9 class Program 10 { 11 12 //在下面的数组存储我们游戏地图各个关卡 13 //数组的小标为0的元素对应地图上的第一格 下标为1的元素对应第二格...下标为n的元素对应n+1

上帝掷骰子吗:量子物理史话

body { font-family: Microsoft YaHei UI,"Microsoft YaHei", Georgia,Helvetica,Arial,sans-serif,宋体, PMingLiU,serif; font-size: 10.5pt; line-height: 1.5; } html, body { } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bo

掷骰子

问题: 游戏规则: 两个人轮流掷骰子6次,并将每次投掷得点数累加起来,点数多者获胜. 要求求出玩家玩100局之后谁是最终的获胜者. #include <stdio.h> #include <stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char *ar

【Java自学】掷骰子游戏

1 package codeTask_FangFa; 2 /*5.29 掷骰子游戏. 规则: 3 扔两个骰子,计算和. 2.3或12(称作掷骰子)你就输了,7或11(称作自然),你就赢了.如果是其他数字. 4 继续掷,直到出来一个7(你输了)或者出来一个和刚才一样的(你赢了). 5 */ 6 7 import java.util.Random; 8 public class ZhiTouZi { 9 public static void main(String[] args){ 10 11 Sy

上帝掷骰子吗? 计算机程序构造解释 奇思妙想-摘要

书籍部分概要 上帝掷骰子吗-量子物理史话 假如一个物理概念是无法测量的,它就是没有意义的.对于这个物我合一的世界来说,任何东西都应该是可以测量和感知的.只有可观测的量才是存在的!(不完全性定理,海森堡不确定性原理 低维世界无法感知高维世界,即解释高维世界.或者我相信原子是四维的或者是多维的总之是高于三维世界存在的,所以表现出波力二象性 .)二维度的语言无法描述高维信息,因此语言或表述方法决定了我们能看的多远. 理论决定了我们能够观察什么,(即同样的心智模式.一个人的认知决定了 他能观察到什么事物