POJ 1009 Edge Detection

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章