POJ 1009: Edge Detection

来源:互联网 发布:中国网络购物发展现状 编辑:程序博客网 时间:2024/05/16 19:53

解题要点: 想清楚输出图像 RLE 编码的各个数据头可能出现的位置.
对输出图像的每个像素都进行计算是不切实际的, 因为时间复杂度太高. 对 RLE 编码进行解码也是不切实际的, 因为空间复杂度太高. 唯一的解决办法, 只有想清楚输出图像 RLE 编码的各个数据头可能出现的位置, 然后仅对这些可能位置进行计算.
事实上, 若设 p 为输入图像的任一数据头在图像中的位置, 则除了左上角和左下角之外, 输出图像的其余数据头都只可能出现在下列 8 个位置之中:

  • p - width - 1, p - width, p - width + 1,
  • p - 1, p + 1,
  • p + width - 1, p + width, p + width + 1.

上述结论证明起来并不麻烦, 画几个图就可以弄清楚. 破解了这个关窍之后, 这道题也就不神秘了.
编程时, 可考虑在输入图像的后部增加一个扩充像素, 其坐标为 width * height, 其值等于 width * height - 1 处的像素值. 这样做可以使左下角不再具有特殊性, 并且有利于程序中的一些循环结构的实现. 对于输出图像, 也可以做相似的处理.

代码如下:

代码中有一些注释掉的内容, 注释掉的原因是其对于本题目无用. 如果对这些内容进行反注释, 则代码中的 Image 类会具有更强的鲁棒性, 从而成为一个实用的类.

#include <iostream>#include <set>#include <cmath>#include <algorithm>using namespace std;typedef pair<long, int> Rle;const int& ( *iMax )( const int&, const int& ) = max<int>;class Image {    protected://      bool bFinished; // 此锁定机制能够提升鲁棒性, 在本题目中无用.        set<Rle> src;        set<Rle> dst;        int width;        long length;        int getVal( const long& pixelPos, set<Rle>::const_iterator& relPos ) const;        void calcPixel( const long& pixelPos, set<Rle>::const_iterator relPos );        void edgeDetect();    public:        Image( const int& width_ );        void push( const int& val, const long& len );        void finish();        void print();};Image::Image( const int& width_ ) : width( width_ ), length( 0 )/*, bFinished( false )*/ {}void Image::push( const int& val, const long& len ) {//  if( bFinished ) {//      return;//  }    src.insert( Rle( length, val ) );    length += len;}int Image::getVal( const long& pixelPos, set<Rle>::const_iterator& relPos ) const {    if( relPos->first <= pixelPos ) {        while( relPos->first < pixelPos ) {            ++relPos;        }        if( relPos->first > pixelPos ) {            --relPos;        }    } else {        do {            --relPos;        } while( relPos->first > pixelPos );    }    return relPos->second;}void Image::calcPixel( const long& pixelPos, set<Rle>::const_iterator relPos ) {    if( pixelPos < 0 || pixelPos >= length ) {        return;    }    const int val = getVal( pixelPos, relPos );    int dstVal = 0;    long tmpPos;    tmpPos = pixelPos - width - 1;  // 左上    if( tmpPos >= 0 && tmpPos % width != width - 1 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    ++tmpPos;   // 上    if( tmpPos >= 0 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    ++tmpPos;   // 右上    if( tmpPos > 0 && tmpPos % width != 0 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    tmpPos = pixelPos - 1;  // 左    if( tmpPos >= 0 && tmpPos % width != width - 1 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    tmpPos += 2;    // 右    if( tmpPos < length && tmpPos % width != 0 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    tmpPos = pixelPos + width - 1;  // 左下    if( tmpPos < length && tmpPos % width != width - 1 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    ++tmpPos;   // 下    if( tmpPos < length ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    ++tmpPos;   // 右下    if( tmpPos < length && tmpPos % width != 0 ) {        dstVal = iMax( abs( getVal( tmpPos, relPos ) - val ), dstVal );    }    dst.insert( Rle( pixelPos, dstVal ) );}void Image::edgeDetect() {    calcPixel( 0, src.begin() );    // 左上角    for( set<Rle>::const_iterator pos = src.begin(); pos != src.end(); ++pos ) {        calcPixel( pos->first - width - 1, pos );   // 左上        calcPixel( pos->first - width, pos );   // 上        calcPixel( pos->first - width + 1, pos );   // 右上        calcPixel( pos->first - 1, pos );   // 左        calcPixel( pos->first + 1, pos );   // 右        calcPixel( pos->first + width - 1, pos );   // 左下        calcPixel( pos->first + width, pos );   // 下        calcPixel( pos->first + width + 1, pos );   // 右下    }    dst.insert( Rle( length, -1 ) );    for( set<Rle>::iterator pos = dst.begin(); pos != dst.end(); ++pos ) {        set<Rle>::iterator pos2 = pos;        ++pos2;        while( pos2 != dst.end() ) {            if( pos2->second != pos->second ) {                break;            }            set<Rle>::iterator tmp = pos2;            ++pos2;            dst.erase( tmp );        }    }}void Image::finish() {//  if( bFinished ) {//      return;//  }    src.insert( Rle( length, src.rbegin()->second ) );//  bFinished = true;    edgeDetect();}void Image::print() {//  if( !bFinished ) {//      return;//  }    cout << width << endl;    set<Rle>::const_iterator pos = dst.begin();    set<Rle>::const_iterator pos2 = pos;    ++pos2;    for( ; pos2 != dst.end(); ++pos, ++pos2 ) {        cout << pos->second << " " << pos2->first - pos->first << endl;    }    cout << "0 0" << endl;}int main() {    int width;    int val;    long len;    while( cin >> width && width != 0 ) {        Image img( width );        while( cin >> val >> len && ( val != 0 || len != 0 ) ) {            img.push( val, len );        }        img.finish();        img.print();    }    cout << 0 << endl;}
0 0
原创粉丝点击