POJ 1009 Edge Detection(图像边缘检测)

256 篇文章 0 订阅

Description
给出一张数字图,对于每个像素点求出这个点与其周围所有点差的绝对值的最大值
这里写图片描述
Input
多组输入,每组数据第一行为一个整数n(n<=1000),表示图的宽度,接下来每行两个整数a,b(a<=255,b<=10^9),分别表示此段数字大小和长度,每组数据以0 0结束,n=0时结束输入
Output
对于每组输入,在求出每个像素点与其周围点差的绝对值后按输入格式输出,即第一行为n,中间为每个数字连续段的数值和长度,以0 0结束每组输出,以0结束全部输出
Sample Input
7
15 4
100 15
25 2
175 2
25 5
175 2
25 5
0 0
10
35 500000000
200 500000000
0 0
3
255 1
10 1
255 2
10 1
255 2
10 1
255 1
0 0
0
Sample Output
7
85 5
0 2
85 5
75 10
150 2
75 3
0 2
150 2
0 4
0 0
10
0 499999990
165 20
0 499999990
0 0
3
245 9
0 0
0
Solution
首先暴力必挂QAQ
然后从答案可以看出肯定会有一些连续段答案相同,所以思路就是,先找出在原图的某一连续段中,答案值可能改变的几个像素(做标记),再一次次跳跃到这几个像素中计算它们的答案值,但是问题是,怎么样的像素才是需要计算的像素。
这里写图片描述
如上图一个map,紫色标注的都是要标记的格子,红色边框的代表这一个连续段的起始格。我们可以发现,每个连续段的起始格,都是要标记的格子,同时,每个要标记的格子,都是一个连续段起始格的周围8个格子中的一个。所以,只需要一个个枚举每个连续段的起始格,并计算它和它四周8个格子的答案值,最后统计答案的时候按照位置先后排序,答案中相同的连续段就合并。因为最多只有1000个连续段,所以不管是时间还是空间都不会超。
这里写图片描述
Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define size 1005
struct pix
{
    int pos;//pos表示这个像素点的位置 
    int code;//code表示这个像素点的答案值 
}outmap[size*8];

int inmap[size][2];//inmap[][0]表示这个连续段的数值,inmap[][1]表示这个连续段的长度 
int width,cntp,tot;//width为图宽度,cntp为图中连续段段数,tot为图中像素点总个数 

int cmp(pix x,pix y)//排序函数,对pos升序排 
{
    return x.pos<y.pos;
}
int getnum(int pos)//返回原图上pos位置上的数值 
{
    int p=0,i=0;
    while(p<pos)
        p+=inmap[i++][1];
    return inmap[i-1][0];
}
int getcode(int pos)//计算pos位置上的答案 
{
    int num=getnum(pos),ret=0;
    int row=(pos-1)/width;//pos所处排数 
    int col=(pos-1)%width;//pos所处列数 
    for(int i=row-1;i<=row+1;i++)//枚举pos周围八个方向 
        for(int j=col-1;j<=col+1;j++)
        {
            int tpos=i*width+j;
            if(i<0||j>=width||j<0||tpos==pos-1||tpos>=tot)
                continue;
            int temp=getnum(tpos+1);
            if(ret<abs(temp-num))
                ret=abs(temp-num);
        }
    return ret;
}

int main()
{
    while(scanf("%d",&width)&width>0)
    {
        int num,len;
        cntp=tot=0;//初始化 
        while(scanf("%d%d",&num,&len)&&len>0)
        {
            inmap[cntp][0]=num;
            inmap[cntp++][1]=len;
            tot+=len;
        }
        printf("%d\n",width);//按格式输出 
        int pos=1,k=0;
        for(int p=0;p<=cntp;p++)//枚举每个连续段 
        {
            int row=(pos-1)/width;//每个连续段起始点所处行数 
            int col=(pos-1)%width;//每个连续段起始点所处列数 
            for(int i=row-1;i<=row+1;i++)//枚举起始点周围八个点 
                for(int j=col-1;j<=col+1;j++)
                {
                    int tpos=i*width+j;//此处tpos其实是真实tpos标号减一 
                    if(i<0||j<0||j>=width||tpos>=tot)//超出图范围舍去 
                        continue;
                    outmap[k].pos=tpos+1;
                    outmap[k++].code=getcode(tpos+1);
                }
            pos+=inmap[p][1];//跳跃到下一连续段起始点 
        }
        sort(outmap,outmap+k,cmp);//对答案按pos升序排序 
        pix temp=outmap[0];
        for(int i=0;i<k;i++)
        {
            if(outmap[i].code==temp.code)//连续则不输出 
                continue;
            printf("%d %d\n",temp.code,outmap[i].pos-temp.pos);
            temp=outmap[i];
        }
        printf("%d %d\n",temp.code,tot-temp.pos+1);//最后一部分 
        printf("0 0\n");//按格式输出 
    }
    printf("0\n");//按格式输出 
    return 0;   
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值