PKU1009解题

今天做到PKU第1009题,将题目描述读了三四遍,也没看懂到底是何意,可能是英文太差了吧,于是乎,偷取捷径,去网上了搜了一下,嘿,还真的搜了一篇关于此题的中文描述,原文链接如下:

http://www.nocow.cn/index.php/PKU/1009

 

其中提到游程长度编码,其意是相同的一串数字用一个pair对来表示,比如若有100个80连续,那就用100 80来表示,这个是理解题意的关键。

现在理解题意了,也要开始思索了,想用什么方法来解决它,题目说最多有最多1000个游程表示,而所有的图像包括2-1,000,000,000个像素,这数据量也太惊人了,要想个法子才行。

 

悲剧,我前后用了将近一个周的时间,想出了个算法,并实现了,在G++也测试通过了,用时感觉也不多,且PKU1009上的示例数据进行测试,结果也都准确无误,可一Judge, 又是TLE。心里这个难受啊。

 

不管结果如何,先把解题思路说下:

1)将输入的每个图像数据对用二维数组存储,列长为3,其中第i行第0列代表的是该数据对的第一个元素在图像数据中的位置,图像数据的每一个像素顺序排序,从0开始,最后一个是像素总数减1;第i行第1列代表是该数据对总共有多少个;第i行第2列代表是该数据值;譬如:对于PKU1009上输入的第一组数据,这样存储:(0,4,15),(4,15,100),(19,2,25),(21,2,175),(23,5,25),(28,2,175),(30,5,25)

2)对每一组图像数据对循环处理: 判断每个像素的位置,是左,是右,是上,是下,是左上,左下,右上,右下,分别处理,对于内部的元素,分为两种情况,一种是判断其数据量是否巨大,若巨大,那肯定中间一部分经计算后的像素值为0,这一部分就没有必须进行计算了,这样可以节约时间,中间这一部分在原图像数据中的区间位置一定要算法好,不然会有错误的。

 

附上源代码,若有人指出费时所在,不胜感激。

#include<iostream>
using namespace std;
#define MAX_PAIR 1000
long source_data[MAX_PAIR][3]; //此为图像对数据
long width,height; //图像的宽度及其高度
int no; //共有多少图像对

 

//获取位置pos在图像中的像素值
int get_value(long pos)
{
    for(int i=0;i<no-1;i++)
    {
        if(pos>=source_data[i][0]&&pos<source_data[i+1][0])
            return source_data[i][2];
    }
   
    return source_data[no-1][2];
}

 

//求两个数相减后的绝对值
int abs_sub(int a,int b)
{
    return a-b<0?b-a:a-b;
}

 

//计算位置在center处的像素输出的像素值

int calc_value(int left_top,int up_top,int right_top,int left_mid,int center,int right_mid,int left_bottom,int down_bottom,int right_bottom)
{
    int max=abs_sub(left_top,center);
   
    if(abs_sub(up_top,center)>max)
        max=abs_sub(up_top,center);

    if(abs_sub(right_top,center)>max)
        max=abs_sub(right_top,center);

    if(abs_sub(left_mid,center)>max)
        max=abs_sub(left_mid,center);

    if(abs_sub(right_mid,center)>max)
        max=abs_sub(right_mid,center);

    if(abs_sub(left_bottom,center)>max)
        max=abs_sub(left_bottom,center);

    if(abs_sub(down_bottom,center)>max)
        max=abs_sub(down_bottom,center);

    if(abs_sub(right_bottom,center)>max)
        max=abs_sub(right_bottom,center);

    return max;
}

 

//如果在图像第一行

int res_top(long pos)
{
    int temp=get_value(pos);
    return calc_value(temp,temp,temp,get_value(pos-1),temp,get_value(pos+1),get_value(pos+width-1),get_value(pos+width),get_value(pos+width+1));
       
}

 

//如果在图像左边列

int res_left(long pos)
{
    int temp=get_value(pos);
    return calc_value(temp,get_value(pos-width),get_value(pos-width+1),temp,temp,get_value(pos+1),temp,get_value(pos+width),get_value(pos+width+1));
}

 

//如果在图像右边列

int res_right(long pos)
{
    int temp=get_value(pos);
    return calc_value(get_value(pos-width-1),get_value(pos-width),temp,get_value(pos-1),temp,temp,get_value(pos+width-1),get_value(pos+width),temp);
}

 

//如果在图像最后一行

int res_bottom(long pos)
{
    int temp=get_value(pos);
    return calc_value(get_value(pos-width-1),get_value(pos-width),get_value(pos-width+1),get_value(pos-1),temp,get_value(pos+1),temp,temp,temp);
}

 

//左上角

int res_top_left(long pos)
{
    int temp=get_value(pos);
    return calc_value(temp,temp,temp,temp,get_value(pos),get_value(pos+1),temp,get_value(pos+width),get_value(pos+width+1));
}

 

//右上角

int res_top_right(long pos)
{
    int temp=get_value(pos);
    return calc_value(temp,temp,temp,get_value(pos-1),get_value(pos),temp,get_value(pos+width-1),get_value(pos+width),temp);
}

 

//左下角

int res_bottom_left(long pos)
{
    int temp=get_value(pos);
    return calc_value(temp,get_value(pos-width),get_value(pos-width+1),temp,temp,get_value(pos+1),temp,temp,temp);
}

 

//右下角

int res_bottom_right(long pos)
{
    int temp=get_value(pos);
    return calc_value(get_value(pos-width-1),get_value(pos-width),temp,get_value(pos-1),temp,temp,temp,temp,temp);
}

 

//内部,非边界

int res_normal(long pos)
{
    return calc_value(get_value(pos-width-1),get_value(pos-width),get_value(pos-width+1),get_value(pos-1),get_value(pos),get_value(pos+1),get_value(pos+width-1),get_value(pos+width),get_value(pos+width+1));
}

 

//获取像素pos在图像中的列号, 以0始
long get_col(long pos)
{
    return pos%width;
}

 

//获取像素pos在图像中的行号, 以0始

long get_lin(long pos)
{
    return (pos-get_col(pos))/width;
}

 

//主函数

int main()
{
    int value,i,res_value=0; //value:输入图像数据对的数据值,res_value: 输出图像数据对的数据值
    long pos=0,size,res_size=0; //pos:当前的像素的序号,size:输入图像数据对的长度,res_size:输出图像数据对的长度
    no=0; 
    while(cin>>width)
    {
        if(width==0)
        {
            cout<<0<<endl;
            return 0;
        }
       
        while(cin>>value>>size)
        {
            if(value==0&&size==0)
            {

                //图像数据输入完成,开始处理输入图像数据

                cout<<width<<endl;
                height=pos/width;
                res_value=res_top_left(0);
                res_size=0;

                for(i=0;i<no;i++)
                    for(pos=source_data[i][0];pos<source_data[i][0]+source_data[i][1];pos++)
                    {
                        long col=get_col(pos);
                        long lin=get_lin(pos);
                        int temp;

                        //判断当前像素的位置,上?下?左?右?左上?左下?右上?右下?内部?

                        if(lin==0&&col==0)
                        {
                            temp=res_top_left(pos);
                        }
                        else if(lin==0&&col==width-1)
                        {
                            temp=res_top_right(pos);
                        }
                        else if(lin==height-1&&col==0)
                        {
                            temp=res_bottom_left(pos);
                        }
                        else if(lin==height-1&&col==width-1)
                        {
                            temp=res_bottom_right(pos);
                        }
                        else if(lin==0)
                            temp=res_top(pos);
                        else if(lin==height-1)
                            temp=res_bottom(pos);
                        else if(col==0)
                            temp=res_left(pos);
                        else if(col==width-1)
                            temp=res_right(pos);
                        else
                        {

                            //在内部,将大数据对的中间置0,跳过为0的区间,往下面计算

                            if(source_data[i][0]+width+1==pos&&source_data[i][0]+source_data[i][1]-width-1>source_data[i][0]+width+1)
                            {
                                temp=0;
                                if(temp==res_value)
                                {
                                    res_size+=source_data[i][1]-2*width-2;
                                }
                                else
                                {
                                    cout<<res_value<<" "<<res_size<<endl;
                                    res_value=0;
                                    res_size=source_data[i][1]-2*width-2;
                                }
                                pos=source_data[i][0]+source_data[i][1]-width-2;
                                continue;
                            }
                            else
                                temp=res_normal(pos);
                        }

                        if(temp==res_value)
                            res_size++;
                        else
                        {
                            cout<<res_value<<" "<<res_size<<endl;
                            res_value=temp;
                            res_size=1;
                        }
                    }
                cout<<res_value<<" "<<res_size<<endl;
                cout<<0<<" "<<0<<endl;
                no=0;
                pos=0;
                break;
            }

 

            //构建输入数据对数据

            source_data[no][0]=pos;
            source_data[no][1]=size;
            source_data[no][2]=value;

            pos+=size;   
            no++;       
        }

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值