POJ 1009 Edge Detection

来源:互联网 发布:红警2 mac os10.12 编辑:程序博客网 时间:2024/05/16 18:12

Google面试受挫,听说以后找实习找工作都会考这样的题目,决定在百忙中一天至少写一道题,题目从poj百练上找。

Edge Detection是一道模拟类题目,但是如果逐个pixel进行计算,妥妥的TLE+MLE,思考半天无果,看了这篇博客以后明晰了思路,http://leons.im/posts/poj-1009-edge-detection-report/。

我们解决这道题的本质是寻找转换后的图片中,每一串value中的第一个值的位置,我们把这个点称为输出起始点,找到所有的可能的输出起始点就能得到输出的结果。

在上面的博客中,证明的一个核心定理在于,一个输出起始点的周围八个点中,一定至少有一个输入起始点。那么反过来,根据所有的输入起始点,可以找到所有可能的输出起始点,把这些所有的输出起始点找出来,处理一下就能得到输出结果。

具体的证明过程上面的博客写的很好,我这里再说一下细节上的问题:

1、要把height*width这个位置的点(也就是最后一个点的下一行的第一个点)作为输入起始点,不然的话左下角的这个点不符合上述定理;

2、在计算某个点和周围的点的最大距离的时候,考虑这个点的位置,即左边界还是右边界还是中间,而上下边界,反正在get_value()的时候也找不出相应的值,所以上下边界的情况其实不用考虑。

#include <iostream>#include <algorithm>#include <memory.h>#include <cmath>using namespace std;#define MAX_PAIRS 1005//用于记录有可能成为处理过后的图片的起始点的点 struct output_point{public:    int value;    int pos;    bool operator< (output_point b){        if(this->pos < b.pos)            return true;        return false;    }};output_point points[MAX_PAIRS*8];int output_count = 0;int width = 0;//用于记录输入数据 int pairs[MAX_PAIRS][2] = {0};//用于记录输出的结果 int ans[MAX_PAIRS][2] = {0};//给定一个pixel在所有pixel中的位置,返回这个pixel对应的值,如果越出图片外,则返回-1 int get_value(int pos, int pair_count){    if(pos <= 0){        return -1;    }    for(int i=0;i<pair_count;i++){        if(pos <= pairs[i][1]){            return pairs[i][0];        }        else{            pos -= pairs[i][1];        }    }    return -1;}//给定一个pixel的中心点,计算这个点和周围的点的最大距离,并且记录到points数组中,成为待定的起始点 void cal_dis(int pos, int pair_count,int width){    int center = get_value(pos, pair_count);    if(center == -1)        return;    //分成四种情况考虑,考虑这个点是在图片的左边缘,右边缘还是中间,另外考虑了width=1这种同时接触左右边缘的情况     int p[4][8] =  {{0,0,0,-width,width,1,1-width,1+width},                    {-1,-1+width,-1-width,-width,width,1,1+width,1-width},                    {-1,-1+width,-1-width,-width,width,0,0,0},                    {0,0,0,-width,width,0,0,0}};    int case_num = -1;    if(width == 1)        case_num = 3;    else if(pos%width == 1)        case_num = 0;    else if(pos%width == 0)        case_num = 2;    else        case_num = 1;    //计算和周围点的距离的最大值     int max_dis = 0;    for(int i=0;i<8;++i){        int t_pos = pos + p[case_num][i];        int t_dist = get_value(t_pos,pair_count);        if(t_dist != -1){            t_dist = abs(t_dist - center);            if(t_dist > max_dis)                max_dis = t_dist;        }    }    points[output_count].pos = pos;    points[output_count].value = max_dis;    output_count ++;    return;}//给定一个输入数据的起始点,这个点周围的八个点都有可能成为输出数据的起始点 void cal_point(int pos, int pair_count,int width){    int p[9] = {-1,-1-width,-1+width,-width,width,1,1-width,1+width,0};    for(int i=0;i<9;++i){            cal_dis(pos+p[i], pair_count,width);    }    return;}int main(){    while(true){        scanf("%d",&width);        if(width == 0)            break;        memset(pairs,0,sizeof(pairs));        memset(points,0,sizeof(points));        memset(ans,0,sizeof(ans));        output_count = 0;        int pair_count = 0;        int value, length;        while(true){            scanf("%d%d",&value,&length);            if(value == 0 && length == 0)                break;            pairs[pair_count][0] = value;            pairs[pair_count][1] = length;            pair_count += 1;        }        //找到所有的输入数据的起始点坐标         int current = 0;        for(int i=0;i<pair_count;++i){            int start_point = current + 1;            cal_point(start_point,pair_count,width);            current += pairs[i][1];        }        cal_point(current + 1,pair_count,width);        sort(points,points + output_count);        //根据所得到的起始点坐标,得到输出结果         int ans_count = 0;        for(int i=0;i<output_count;++i){            if(i==0){                ans[ans_count][0] = points[0].value;                ans[ans_count][1] = points[0].pos;                ans_count ++;                continue;            }            if(points[i].value != ans[ans_count-1][0]){                ans[ans_count-1][1] = points[i].pos - ans[ans_count-1][1];                ans[ans_count][0] = points[i].value;                ans[ans_count][1] = points[i].pos;                ans_count++;            }        }        ans[ans_count-1][1] = current + 1 -ans[ans_count-1][1];        printf("%d\n",width);        for(int i=0;i<ans_count;++i){            printf("%d %d\n",ans[i][0],ans[i][1]);        }        printf("0 0\n");    }       printf("0\n");    return 0;}
原创粉丝点击