连通问题 解题报告 ——2011软件大赛决赛 C组 本科第5题 原创By BossDong

原创 By BossDong。

题目如下:

BMP是常见的图像存储格式。
如果用来存黑白图像(颜色深度=1),则其信息比较容易读取。

与之相关的数据:

(以下偏移均是从文件头开始)
偏移:10字节, 长度4字节: 图像数据真正开始的位置。
偏移:18字节, 长度4字节: 位图的宽度,单位是像素。
偏移:22字节, 长度4字节: 位图的高度,单位是像素。


从图像数据开始处,每个像素用1个二进制位表示。
从图片的底行开始,一行一行向上存储。

Windows规定图像文件中一个扫描行所占的字节数必须是4字节的倍数,
不足的位均以 0 填充。例如,图片宽度为45像素,实际上每行会占用
8个字节。

可以通过Windows自带的画图工具生成和编辑二进制图像。
需要在“属性”中选择“黑白”,指定为二值图像。
可能需要通过 查看 | 缩放 | 自定义... 把图像变大比例一些,
更易于操作。

图像的左下角为图像数据的开始位置。白色对应1,黑色对应0

我们可以定义:两个点距离如果小于2个像素,则认为这两个点连通。
也就是说:以一个点为中心的九宫格中,围绕它的8个点与它都是连通的。
如:t1.bmp 所示,左下角的点组成一个连通的群体;
而右上角的点都是孤立的。

程序的目标是:根据给定的黑白位图,分析出所有独立连通的群体,
输出每个连通群体的面积。所谓面积,就是它含有的像素的个数。

输入数据固定存在in.bmp中。

如示例的in.bmp,
程序应该输出:
12
81
52
133

该输出表示:共有4个连通群体。
输出的连通体面积间的顺序可以随意。

请编程解决上述问题。

我们测试程序的时候,会使用不同的in.bmp文件。


要求考生把所有函数写在一个文件中。调试好后,存入与考生文件夹下对应题号的“解答.txt”中即可。
相关的工程文件不要拷入。
对于编程题目,要求选手给出的解答完全符合ANSI C标准,不能使用c++特性;
不能使用诸如绘图、中断调用等硬件相关或操作系统相关的API。


解题思路:

我觉得本题难度在对一下几句话的理解上:

偏移:10字节, 长度4字节: 图像数据真正开始的位置。
偏移:18字节, 长度4字节: 位图的宽度,单位是像素。
偏移:22字节, 长度4字节: 位图的高度,单位是像素。

熟悉bmp图像存储的,估计很容易理解。

其实,就是文件头,定好的格式,所有的文件都是010101存储的,但是、加上文件头后,才有丰富多彩的文件格式等等。

按照他上边的提示,使用fread和fseek进行文件指针定位和读数据

分别读出图片宽和高度。

然后用递归算法就OK了。

以下是代码(没填啥注释,以前写的,现在发上来,有空填注释):

#include <stdio.h>
#include <stdlib.h>
char *q;
int width=0,height=0,t_width=0;
int f(int x,int y)
{
	if(x>=width||x<0||y<0||y>=height)
	{
		return 0;
	}
	char *temp=(q+(t_width*y+x));
	if(*temp=='0')
	{
		*temp='1';
		return f(x-1,y)+f(x,y-1)+f(x-1,y-1)+f(x,y+1)
		  +f(x+1,y)+f(x+1,y+1)+f(x+1,y-1)+f(x-1,y+1)+1;
	}
	else
		return 0;
}
int main()
{
      FILE *fp;
      if((fp=fopen("in.bmp","r"))==NULL)
      {
         printf("打开文件失败!");
         return 0; 
      } 
      fseek(fp,18L,0);
      int start=0,size=0;
      fread(&width,sizeof(int),1,fp);
      fseek(fp,22L,0);
      fread(&height,sizeof(int),1,fp);
      fseek(fp,10L,0);
	  fread(&start,sizeof(int),1,fp);
	  fseek(fp,start,0);
	  if((width%32)==0)
	  {
		  t_width=width;
	  }
	  else
	  {
		  t_width=(width/32+1)*32;
	  }
	  size=height*(t_width/8);
      char *p=(char *)malloc(size*sizeof(char));
      fread(p,sizeof(int),size,fp);
	  fclose(fp);
	  int i=0,j=0;
	  q=(char *)malloc(size*32*sizeof(char));
	  char *temp=q;
	  char iMask=128;
	  for(j=0;j<size;j++)
	  {
		  iMask=128;
		  for( i=0 ; i<8 ; i++ )
		  {
			  if((*p & iMask)==0)
			  {
				*temp='0';
			  }
			  else
			  {
				*temp='1';
			  }
			  iMask = iMask >> 1;
			  if(iMask<0)
			  {
				iMask=iMask-128;
			  }
			  temp++;
		  }
		  p++;
	  }
	  for(j=0;j<height;j++)
	  {
		  
		  for(i=0;i<t_width;i++)
		  {
			  printf("%c",*(q+(t_width*j+i))=='1'?' ':'0');
		  }
		  printf("\n");
	  }
	  for(j=0;j<height;j++)
	  {
		  
		  for(i=0;i<t_width;i++)
		  {
			  if(*(q+(t_width*j+i))=='0')
			  {
				 printf("%d\n",f(i,j));
			  }
		  }
	  }
      system("pause");
      return 0; 
}

本题的代码我已经上传资源: 点我下载





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值