POJ 1008 Edge detection

原题见:

POJ 1008 Edge detection


由于题中说明输入的图像input image可能会有2 to 1,000,000,000 (109) 个像素,所以如果对输出图像output image的每一个像素都用枚举的方法去计算的话肯定会是超时的。所以需要找到一种方法来简化定种计算。自己在纸上也推了好久,没有找到。于是google了一下,发现一个解决的方法。网址是:POJ 1008 Edge detection report

是英文的,写的很简练,下面就解释一下。

对于入输入

7
15 4
100 15
25 2
175 2
25 5
175 2
25 5
0 0
假设用width来存储图片像素点的宽度,则这时width=7

而输入的每一组数据都看成是一个序对用<val[i],len[i]>表示。而对于每一序数对在图片中的位置,都可以用row[i]和col[i]来表示。

当然output image也是按这种方法来表示。

为了解决该问题,下面先证明一个假设:

证明:对于output image中的每一组连续元素的第一个元素(称为元素起点或起点元素),它在数组对应的位置上一定至少与input image中的某个元素起点相邻。这里的相邻是指像扫雷游戏中的那种相邻。


img1



则像素2的想念元素为图中插红旗的点,也就是说,如果在output image中,如是2是元素起点,那么,在input image中与output插红旗对应的位置一定有一个是元素起点。

这个证明过程原文里也没给清楚,也可能是我没有看懂吧。

有时间的同学可以证明一下啦。

因为我们在output image中,我们只需要找到所有起点元素及其长度就可以了,所以这个假设告诉我们,在那些不可能成为元素起点的位置上,我们就不用计算了。

如:下图中对于input image中打叉的像素我们就不用计算,因为它不与任何起点元素相邻,所以这些位置在Output image中不可能成为元素起点。

img2

这个35个像素的image我们只是少计算了6个像素点,然而对于更大的稀疏像素矩阵的话,其减少的计算量是相当大的,如输入用例

10

30 500000000

200 500000000

0 0

读了一遍原网站的代码之后,没想到竟然记住于是就写下来了。

代码如下:

#include<stdio.h>

#define N 1010

int inData[N][2];
typedef struct node{
    int val,pos;
} node;		//因为对应的每一个像素起点,都要计算其相邻的9个像素点,这样就有可能有在输出图像中有对应的9个输出点。

node outData[N*9];
int inNum,outNum;	//inNum,用于记录input image中像素起点的个数,outNum用于记录output image中像素起点的个数。
int total,width;		//对input image数组进行行编址的话,用于记录一维线性数组中像素起点的起点位置。,width为行宽。

int getVal(int pos){
   int  low=0,high=inNum-1;
   while(low<=high){
       int mid=(low+high)/2;
       if(inData[mid][1]<=pos)
	   low=mid+1;
       else
	   high=mid-1;
   }
   return inData[high][0];
}

int calc(int pos){
    int i,j,row,col,p;
    row=pos/width;
    col=pos%width;
    int ret=0,tmp;
    for(i=row-1;i<=row+1;i++)
	for(j=col-1;j<=col+1;j++){
	  p=i*width+j;
	  if(i<0||j<0||j>=width||p>=total||p==pos)
	      continue;
          tmp=abs(getVal(pos)-getVal(p));
	  if(tmp>ret)
	      ret=tmp;
	  }
     return ret;
}

int cmp(const void *ele1,const void *ele2){
    return ((node *)ele1)->pos-((node *)ele2)->pos;
}
void solve(void){
   int i,j,k;
   int row,col,pos;
   outNum=0;
   for(i=0;i<=inNum;i++){
       row=inData[i][1]/width;
       col=inData[i][1]%width;
       for(j=row-1;j<=row+1;j++){
	   for(k=col-1;k<=col+1;k++){
	       pos=j*width+k;
	       if(j<0||pos<0||pos>=total)
		   continue;
	       outData[outNum].val=calc(pos);
	       outData[outNum].pos=pos;
	       outNum++;
	   }
       }
   }
   qsort(outData,outNum,sizeof(node),cmp);
   node cur=outData[0];
   for(i=0;i<outNum;i++){
       if(cur.val==outData[i].val)
	    continue;
      printf("%d %d\n",cur.val,outData[i].pos-cur.pos);
      cur=outData[i];
   }
   printf("%d %d\n",cur.val,total-cur.pos);
   printf("0 0\n");
}

int main(){
    int i,tmp;
    while(scanf("%d",&width)!=EOF && width){
	printf("%d\n",width);
	total=0;inNum=0;i=0;
	while(scanf("%d%d",&inData[i][0],&inData[i][1])!=EOF){
	    tmp=inData[i][1];
	    inData[i][1]=total;	//记录该像素起点的起始位置。
	    total+=tmp;
	     if(tmp==0)
		break;
	    i++;
	}
	inNum=i;
	solve();
   }
    printf("0\n");
    return 0;
}


在提交该问题的时候,要特别注意,对于输入的第个width都要进行输出的。

最后那个0也要输出,不然会差错的哟,就是因为这相,我都提交错了好几次啦。

Good Luck!!!





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值