原题见:
由于题中说明输入的图像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中的某个元素起点相邻。这里的相邻是指像扫雷游戏中的那种相邻。
则像素2的想念元素为图中插红旗的点,也就是说,如果在output image中,如是2是元素起点,那么,在input image中与output插红旗对应的位置一定有一个是元素起点。
这个证明过程原文里也没给清楚,也可能是我没有看懂吧。
有时间的同学可以证明一下啦。
因为我们在output image中,我们只需要找到所有起点元素及其长度就可以了,所以这个假设告诉我们,在那些不可能成为元素起点的位置上,我们就不用计算了。
如:下图中对于input image中打叉的像素我们就不用计算,因为它不与任何起点元素相邻,所以这些位置在Output image中不可能成为元素起点。
这个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!!!