第四次机考(2019)D. 卫星照片二

这题还是很有意思的。
注意到题目里有一个关键信息:路肯定是贯穿了整张图的,所以实际上路把地图分成了几个区域:
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
0 0 0 0 0 0 0 0 0 0
1 1 0 1 1 0 0 1 1 1
1 1 0 1 1 0 0 1 1 1
(二值化之后的地图)
只要找到横纵方向的街区数,再相乘就好了。

如果真这么简单,岂不美哉。这题的特殊情况比较多,用化归的思想,在3x3区域内,我们可以找到所有的特殊情况。

难点1:街区计数器
我们要数出某一行/列里的街区数时,最先想到的应该是自动机。检查一下你的自动机能不能数出正确的街区数。
1 0 1(应为2个) 0 1 0(应为1个) 1 1 0 (应为1个) 1 1 1 (应为1个) 0 0 1(应为1个)

难点2:特殊情况
最自然的想法当然是只数第一列和第一行的街区数,再相乘,但是遇到这样的
0 0 0
1 1 1
1 1 1
显然就不对,只数第一行话就变成了0,但是实际上第二行有街区。
特别地,还有回字形的情况
0 0 0
0 1 0
0 0 0
所以我们应该逐行逐列去读街区数,取第一个非零的街区数作为行/列的街区数,因为只要出现了街区数不为0的行/列,往下的分布也是这样的(不排除底下还有零行,不过已经无所谓了)。
也可以数道路。

#include <stdio.h>
enum {ROAD,BLOCK};
void preProcess(int**,int,int);//预处理函数,将读取的地图二值化,我们并不关心灰度值的具体数值,只需要知道它代表什么就行了
//这本篇0代表道路,1代表街区,与枚举变量保持一致
void debug_printSheet(int**,int,int);//打印当前的地图状态,有兴趣的可以把main里我注释掉的函数执行试试
int main()
{	
	int m,n,i,j,k,tmp;
	scanf("%d%d",&m,&n);

	int **mainPtr=(int**)malloc(sizeof(int*)*m);
	for(i=0;i<m;i++)
		mainPtr[i]=(int*)malloc(sizeof(int)*n);
	//创建二维动态数组
	preProcess(mainPtr,m,n);//读取并预处理
	//debug_printSheet(mainPtr,m,n);//有兴趣的可以看一下处理后的结果
	int rowCnt,colCnt,rowNow,colNow;//Cnt是Count的简写,rowCnt和colCnt表示行、列各自的街区数,rowNow和colNow表示当前检查的行/列中的街区数
	int state;//自动机状态函数

	for(i=0;i<m;i++)
	{	rowNow=0;//注意每次检查前要重置rowNow
		for(j=0;j<n;j++)
		{	tmp=mainPtr[i][j];//tmp表示当前读取到的格子的值
			if(j==0)//第一次的特殊处理
			{	state=(tmp==ROAD)?ROAD:BLOCK;//如果第一个格子里是ROAD,就把状态设置为ROAD,否则为BLOCK
				if(state==BLOCK) rowNow++;	//检测到BLOCK的话,街区计数器rowNow要加一。		
				continue;
			}
			switch(state)
			//遇到 ROAD->BLOCK转换,即检测到新街区,街区计数器就加一,状态切换。BLOCK->ROAD时只切换状态。
			{	case BLOCK:
					if(tmp==ROAD)
						state=ROAD;
					break;
				case ROAD:
					if(tmp==BLOCK)
					{
						state=BLOCK;
						rowNow++;
					}					
			}			
		}
		if(rowNow!=0) 
			{
				rowCnt=rowNow;//读到第一个非零街区数时,不必再循环了
				break;
			}
	}
	//列同理
	for(j=0;j<n;j++)
	{	
		colNow=0;
		for(i=0;i<m;i++)
		{	
			tmp=mainPtr[i][j];
			if(i==0)
			 {
				state=(tmp==0)?ROAD:BLOCK;
				if(state==BLOCK) colNow++;			
				continue;
			}
			switch(state)
			{
				case BLOCK:
					if(tmp==ROAD)
						state=ROAD;
					break;
				case ROAD:
					if(tmp==BLOCK)
					{
						state=BLOCK;
						colNow++;
					}					
			}			
		}
		if(colNow!=0) 
			{
				colCnt=colNow;
				break;
			}
	}	
	
	printf("%d",rowCnt*colCnt);

	for(i=0;i<m;i++) free(mainPtr[i]);
	free(mainPtr);
	return 0;
}

void preProcess(int **mainPtr,int m,int n)
{
	int tmp,i,j;
	for(i=0;i<m;i++)
		for(j=0;j<n;j++)
		{
			scanf("%d",&tmp);
			mainPtr[i][j]=(tmp<=50)?ROAD:BLOCK;//如果读取到的格子里的值<=50,就记为ROAD(值为0),反之为BLOCK(值为1)
		}
}

void debug_printSheet(int **mainPtr,int m,int n)
{	
	int i,j;
	for(i=0;i<m;i++)
		for(j=0;j<n;j++)
			printf("%d%c",mainPtr[i][j],j==n-1?'\n':' ');
}

题目描述

一张正方形的卫星照片可看作是由多个小方格组合而成的矩阵,每个小方格叫做一个像素点。卫星照片中存在街区和道路,街区是由不同道路或者道路与照片边缘围成的矩形区域,所有道路都纵横排列,每条道路均贯穿整张照片并平行于照片的边缘。各条道路的宽度可能不一样但每一条道路的宽度是固定的,不存在宽窄不均的道路。卫星照片中每个像素点都有灰度值,如果某点的灰度值大于等于0且小于等于50,则该点为道路上的点;如果某点的灰度值大于50,则该点为街区上的点,街区的长和宽也不是固定的。现请你写一段程序,求出照片中一共有多少个街区。
输入:第一行为两个整数m,n(5<=m,n<=100),分别代表像素点的行数和列数。后边是mXn的整数矩阵,每个整数代表一个像素的灰度值(该值大于等于0且小于等于10000)。
输出:只有一行,为一个整数,为照片中街区的总数。

输入样例

10 10
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
50 50 50 50 50 50 50 50 50 50
99 99 50 99 99 50 50 99 99 99
99 99 50 99 99 50 50 99 99 99
输出样例

6

猜你喜欢

转载自blog.csdn.net/weixin_43873801/article/details/86550689
今日推荐