POJ 百练1009 提示

本题看似是一道简单的题,但由于输入的数据量过于庞大,最直接的解法是不能完成的。

该题的最主要思想是发现,只有每段数字的首位及其四周的8个数字有更变的可能,其他数字都与其左位已算出的数字相同。

这样就只用处理1000个数对*9个需要处理的格*9需要计算的数=81000。

如果算法不精依然容易超时。


方法:

1、计算出每个需计算的格子的位置、数值,存入数组中。

2、将数组按位置排序,再按要求从头遍历,计算结果并输出。


然而这样做,该题是有很多bug的,比如:

http://www.educity.cn/wenda/368388.html

详细论述了两种bug。

笔者鼓励你仔细解决这两种bug。

但告诉你一个偷懒的方法:

只要处理一下最后一行的第一个数字就可以了,或者说处理位于总长位置即超过数组大小1的位置的格子,这题poj就能过。

代码:

http://blog.csdn.net/lyy289065406/article/details/6648671


心得:

由于MAP内部采用红黑树结构,因此按理不应该速度很慢的。

但事实上如果插入次数很多,且不需要再插入过程中一直保持顺序,用数组记录再最后qsort要快一些。

qsort速度一直比自己写的快排程序快一点。


#include <iostream>
#include <vector>
#include <cmath>
#include <map>
using namespace std;

int width;
int sum = 0;
map<int, int> MAP;
vector<pair<int, int> > ppvec;

int searchnum(int a) {
	int k = 0, sum = 0;
	while (sum <= a) {
		sum += ppvec[k].second;k++;
	}
	return ppvec[k-1].first;
}
int zuidajueduizhi(int m) {
	int x = m / width, y = m%width;
	int zuida = -1;
	for (int i = -1; i <= 1; i++)
		for (int j = -1; j <= 1; j++) {
			if (x + i >= 0 && x + i < sum / width&&y + j >= 0 && y + j < width) {
				int k = (x + i)*width + y + j;
				int kk = searchnum(k); int km = searchnum(m);
				int kkk = abs(kk - km);
				if (kkk > zuida)zuida = kkk;
			}
		}
	return zuida;
}
void fieldplay() {
	int sum_counter = 0; int x_counter, y_counter;
	for (int i = 0; i <= ppvec.size(); i++) {
		x_counter = sum_counter / width;
		y_counter = sum_counter%width;
		int tmp_counter;
		for (int j = -1; j <= 1; j++) {
			for (int l = -1; l <= 1; l++) {
				tmp_counter = sum_counter + j*width + l;
				if (x_counter + j >= 0 && tmp_counter<sum&&y_counter + l >= 0 && y_counter + l < width) {
					//cout << tmp_counter << ' ' << searchnum(tmp_counter) << endl;
					int m = (x_counter + j)*width + y_counter + l;
					int k = zuidajueduizhi(m);
					MAP.insert(make_pair(m, k));
				}
			}
		}		
		/*if (y_counter > 1 && ppvec[i].second>width - y_counter + 2) { sum_counter = (x_counter + 1)*width; i--; }
		else*/
		if (i >= ppvec.size())break;
			sum_counter += ppvec[i].second;
	}
	return;
}

void reset() {
	MAP.clear();
	ppvec.clear();
	sum = 0;
	return;
}

void print() {
	cout << width << endl;
	pair<int, int> pp = *MAP.begin();
	for (map<int, int>::iterator ii=MAP.begin(); ii != MAP.end(); ii++) {
		if (ii->second == pp.second)continue;
		else {
			int k = ii->first - pp.first;
			cout << pp.second << ' ' << k << endl;
			pp = *ii;
		}
	}
	cout << pp.second << ' ' << sum - pp.first << endl;
	cout << '0' << ' ' << '0' << endl;
	return;
}

int main()
{
	while (cin >> width) {
		if (width == 0)break;
		ppvec.clear();
		int nnum, llen;
		while (cin >> nnum >> llen) {
			if (nnum == 0 && llen == 0)break;
			ppvec.push_back(make_pair(nnum, llen));
			sum += llen;
		}

		fieldplay();
		print();
		reset();
	}
	cout << '0' << endl;
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值