pku acm 1009

-)常规解法,Time Limit Exceeded
设一个点x与周围8个点相减后绝对值的最大值为edv值。
思想:
1)同一行中的相邻点x1,x2,如果x1已经求得它周围的8个点那么对于x2而言只需要计算另外3个点就可以了。
   边界情况就是:对于左边界的点必须求周围8个点
2)当两个相邻点x1,x2的edv值都是0时,检查是否存在接下来很多点值都相等的情况,这那么可以加速。


尽管使用了以上两种技术但是速度仍然不够快,平台通不过。
#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
using namespace std;

#define L_N(x) (x - 1)
#define R_N(x) (x + 1)
#define U_N(x,width) (x - width)
#define D_N(x,width) (x + width)

#define LU_N(x,width) L_N(U_N(x,width))
#define RU_N(x,width) R_N(U_N(x,width))
#define LD_N(x,width) L_N(D_N(x,width))
#define RD_N(x,width) R_N(D_N(x,width))

#define L_BORDER(x,width) (((x-1)%width==0)?1:0)
#define R_BORDER(x,width) (((x)%width==0)?1:0)
#define U_BORDER(x,width) (((x) >= 1 && (x) <= width)?1:0)
#define D_BORDER(x,total,width) (((x) > (total - width) && (x) <= (total))?1:0)

int arr[1000][2];
int width;
int aa[9];
int totalPixs;
int count;

int getPix(int x)//x >= 1
{
	int i;
	for(i = 0; i < count; i++)
	{
		if(x <= arr[i][1])
			return arr[i][0];
	}
	return -1;
}

int getIndex(int x)//x >= 1
{
	int i;
	for(i = 0; i < count; i++)
	{
		if(x <= arr[i][1])
			return i;
	}
	return -1;
}


void get8NPix(int i)
{
	int curPix,tPix;
	curPix = getPix(i);
	int j;
	for(j = 0; j < 9; j++)
		aa[j] = curPix;
	aa[4] = curPix;

	if(!L_BORDER(i,width))
		aa[3] = getPix(L_N(i));
	if(!R_BORDER(i,width))
		aa[5] = getPix(R_N(i));
	if(!U_BORDER(i,width))
		aa[1] = getPix(U_N(i,width));
	if(!D_BORDER(i,totalPixs,width))
		aa[7] = getPix(D_N(i,width));
	if(!(L_BORDER(i,width) || U_BORDER(i,width)))
		aa[0] = getPix(LU_N(i,width));
	if(!(R_BORDER(i,width) || U_BORDER(i,width)))
		aa[2] = getPix(RU_N(i,width));
	if(!(L_BORDER(i,width) || D_BORDER(i,totalPixs,width)))
		aa[6] = getPix(LD_N(i,width));
	if(!(R_BORDER(i,width) || D_BORDER(i,totalPixs,width)))
		aa[8] = getPix(RD_N(i,width));
}

void get3NPix(int i)
{
	aa[0] = aa[1];
	aa[1] = aa[2];
	aa[3] = aa[4];
	aa[4] = aa[5];
	aa[6] = aa[7];
	aa[7] = aa[8];

	aa[2] = aa[5] = aa[8] = -1;
	if(!(R_BORDER(i,width) || U_BORDER(i,width)))
		aa[2] = getPix(RU_N(i,width));
	if(!R_BORDER(i,width))
		aa[5] = getPix(R_N(i));
	if(!(R_BORDER(i,width) || D_BORDER(i,totalPixs,width)))
		aa[8] = getPix(RD_N(i,width));
}

int getMaxDiff(int *aa)
{
	int max = 0;
	int i,diff;
	for(i = 0; i < 4; i++)
	{
		if(aa[i] == -1)continue;
		diff = abs(aa[4] - aa[i]);
		if(diff > max) max = diff;
	}
	for(i = 5; i < 9; i++)
	{
		if(aa[i] == -1)continue;
		diff = abs(aa[4] - aa[i]);
		if(diff > max) max = diff;
	}
	return max;
}

int main()
{
	
	int px, rle;	
	int begin,end,h;
	int i;
	//freopen("in.txt","r",stdin);

	cin>>width;
	while(width)
	{
		cout<<width<<endl;
		totalPixs = count = 0;
		while(cin>>px>>rle)
		{
			if(px == 0 && rle == 0)
				break;
			totalPixs += rle;//
			arr[count][0] = px;
			arr[count][1] = totalPixs;	//
			++count;
		}

		int max,pmax,pcount;
		get8NPix(1);
		pmax = getMaxDiff(aa);
		pcount = 1;
		for(i = 2; i <= totalPixs; i++)
		{
			if(L_BORDER(i,width))
				get8NPix(i);
			else
				get3NPix(i);
			max = getMaxDiff(aa);

			if(max == 0 && pmax == 0)
			{
				h = getIndex(i);

				if(h == 0)
					begin = 0;
				else if(h <= count - 1)
					begin = arr[h-1][1];

				if(i - begin > width)
				{
					end = arr[h][1] - width - 1;
					if(end > i)
					{
						pcount += end - i;
						i = end;
					}
				}
			}

			if(max == pmax)
				++pcount;
			else
			{
				cout<<pmax<<" "<<pcount<<endl;
				pmax = max;
				pcount = 1;
			}
		}
		cout<<pmax<<" "<<pcount<<endl;
		cout<<"0 0"<<endl;

		cin>>width;
	}
	cout<<"0"<<endl;
	return 1;
}

二)下面这种方法来自一位网友,认为只有在输入值发生变化的地方才可能发生edv值的变化。(AC)

如上图中蓝色的方框正是发生输入值变化的点,那么只有这些点及其周围的8个点才可能发生edv值变化。其它点的值都不会变化。

为什么?


现假设从A到B没有发生值变化,且B周围的8个点也没有发生值变化,则很显然d1 = c1 = b1 = a1,d2 = c2 = b2 = a2, d3 = c3 = b3 = a3,因此A的edv值必与B的edv值相等。

因此如果如果从A到B发生edv值变化,那么必然是周围存在输入值变化的点。

对于这题而言,我们只需要计算输入值发生变化处的点及其周围的8个点即可。

#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <map>
using namespace std;

int arr[1002][2];
int width;
int totalPixs;
int count;

bool insideImage(int dx,int dy)//dx >= 1, dy >= 1
{
	if(dx >= 1 && dy >= 1 && dx <= width 
		&& ((dy-1)*width+dx) <= totalPixs
	  )
		return true;
	return false;
}

int getPix(int dx,int dy)//dx >= 1, dy >= 1
{
	int x = (dy-1)*width+dx;
	for(int i = 1; i < count; i++)
	{
		if(x <= arr[i][1])
			return arr[i][0];
	}
	return -1;
}

int getEdv(int dx,int dy)
{
	int cpix = getPix(dx,dy);
	int max = -1,t;
	for(int i = dx-1; i <= dx+1; i++)
		for(int j = dy-1; j <= dy+1; j++)
		{
			if(insideImage(i,j))
			{
				t = abs(cpix-getPix(i,j));
				if(t > max)max = t;
			}
		}
	return max;
}

int main()
{	
	freopen("in.txt","r",stdin);

	int px,rle;
	map<int,int> im;
	map<int,int>::iterator it;
	map<int,int>::iterator tor;

	cin>>width;
	while(width)
	{
		cout<<width<<endl;

		//initiation
		arr[0][1] = 0;
		totalPixs = 0;
		count = 1;
		im.clear();
		
		while(cin>>px>>rle)
		{
			if(px == 0 && rle == 0)
				break;
			totalPixs += rle;//
			arr[count][0] = px;
			arr[count][1] = totalPixs;	//
			//cout<<"arr["<<count<<"][0] = "<<arr[count][0]
			//    <<" arr["<<count<<"][1] = "<<arr[count][1]<<endl;
			++count;
		}				

		{//begin_data_analize
			for(int i = 0; i < count; i++)
			{
				int n = arr[i][1] + 1;//输入值发生变化的点
	
				//求n对应的坐标表示,左上角为(1,1),x增长方向为右,y增长方向为下
				int x,y,dx,dy;
				if(n % width == 0)
					x = width, y = n/width;
				else
					x = n%width, y = n/width + 1;

				//求其点x,y及其周围的8个点的edv值
				for(dx = x-1; dx <= x+1; dx++)				
					for(dy = y-1; dy <= y+1; dy++)
					{
						if(insideImage(dx,dy))												
							im.insert(make_pair(((dy-1)*width+dx), getEdv(dx,dy)));						
					}				
			}			
	
			it = im.begin();
			while(it != im.end())//进行编码输出
			{
				tor = it;
				tor++;
				for(;tor != im.end() && tor->second == it->second;tor++);
				if(tor == im.end())break;
				cout<<it->second<<" "<<(tor->first - it->first)<<endl;
				it = tor;
			}			
			cout<<it->second<<" "<<(totalPixs - it->first + 1)<<endl;
			//cout<<endl;
		}//end_data_analize

		cout<<"0 0"<<endl;
		cin>>width;
	}
	cout<<"0"<<endl;
	return 1;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值