poj 1009 Edge Detection

分类:其他 难度:2

题意:给定一张图的每行长度w,及每个点的像素值,以(像素值,持续长度)对表示,求每个像素和周围8个点的差值绝对值的最大值,结果依然以(像素值,持续长度)表示,点数[2,1e9],给定(像素值,持续长度)对的上限为1000对

 

通过点数的范围可知,这道题不能用O(n)算法遍历,超时;也不能把每个像素点单个存储,超内存。开始考虑对于一个持续长度为len的像素,可知若len超过2w+3,其[w+1,len-w]区间内的点值为0,可省略计算,仍超时。再考虑对某一点,若其上一行从其左上角点开始均为一个像素,其下一行左下角点均为一个像素,且该点不是一个新像素的起始点,则其往后的n个点均为同一个值,n=min(w,上一行像素长度,下一行像素长度,该像素长度),当然还要考虑如果上/下一行为相同元素的情况,以及边界情况。此方法0ms

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define MAX(x,y) (x)>(y)?(x):(y)
#define MIN(x,y) (x)<(y)?(x):(y)
using namespace std;

const int N=1010;
int img[N][2],sum[N];
int w,n,value,length;

void addq(int v,int l)
{
	if(v!=value)
	{
		if(length>0) printf("%d %d\n",value,length);
		value=v;
		length=l;
	}
	else
		length+=l;
}

int checksub(int x,int y,int offset)
{
	int ex=x,ey=y+offset;
	while(ey<0&&ex>=0)
	{
		ex--;
		ey+=img[ex][1];
	}
	if(ex<0) return 0;
	while(ey>=img[ex][1] && ex<n)
	{
		ey-=img[ex][1];
		ex++;
	}
	if(ex>=n) return 0;
	return abs(img[x][0]-img[ex][0]);
}

int check(int x,int y)
{
	int ans=0;
	int num=sum[x]+y;
	if(num>=w)
	{
		if(num%w != 0) ans=MAX(ans,checksub(x,y,-w-1));
		ans=MAX(ans,checksub(x,y,-w));
		if(num%w != w-1) ans=MAX(ans,checksub(x,y,-w+1));
	}
	if(num%w != 0) ans=MAX(ans,checksub(x,y,-1));
	if(num%w != w-1) ans=MAX(ans,checksub(x,y,1));
	if(num<sum[n]-w)
	{
		if(num%w != 0) ans=MAX(ans,checksub(x,y,w-1));
		ans=MAX(ans,checksub(x,y,w));
		if(num%w != w-1) ans=MAX(ans,checksub(x,y,w+1));
	}
	return ans;
}

int getsamelen(int x,int y)
{
	if(y==0||y>=img[x][1]-2) return 1;
	int num=sum[x]+y;
	if(num%w==0 || num%w==w-1) return 1;
	
	int ux=x,uy=y-w-1,dx=x,dy=y+w-1;
	int len=img[x][1]-y-1;
	if(num>=w)
	{
		while(uy<0&&ux>=0)
		{
			ux--;
			uy+=img[ux][1];
		}
		if(img[ux][1]-uy<3) return 1;
		if(ux==x) len=MIN(len,w-num%w);
		else len = MIN(len,img[ux][1]-uy-1);
	}
	if(num<sum[n]-w)
	{
		while(dy>=img[dx][1] && dx<n)
		{
			dy-=img[dx][1];
			dx++;
		}
		if(img[dx][1]-dy<3) return 1;
		if(dx==x) len=MIN(len,MIN(w-num%w,img[x][1]-dy-2));
		else len = MIN(len,img[dx][1]-dy-1);
	}
	return len;
}

int main()
{
	while(scanf("%d",&w)&&w)
	{
		value=length=-1;
		int i,j,a,b;
		sum[0]=0;
		for(i=0;scanf("%d%d",&a,&b)&&(a+b);i++)
		{
			img[i][0]=a;
			img[i][1]=b;
			sum[i+1]=img[i][1]+sum[i];
		}
		img[i][0]=img[i][1]=0;
		n=i;
		printf("%d\n",w);
		for(i=0;i<n;i++)
		{
			int len=img[i][1];
			int ans,samelen;
			for(j=0;j<len&&j<=w;)
			{
				samelen = getsamelen(i,j);
				ans=check(i,j);
				addq(ans,samelen);
				j+=samelen;
			}
			if(len>=2*w+3) 
			{
				addq(0,len-2*w-2);
				j=len-w-1;
			}
			for(;j<len;)
			{
				samelen = getsamelen(i,j);
				ans=check(i,j);
				addq(ans,samelen);
				j+=samelen; 
			}
		}
		printf("%d %d\n",value,length);
		printf("0 0\n");
	}
	printf("0\n");
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值