1. 程式人生 > >離散化_二分_字首和_POJ3179_Corral the Cows

離散化_二分_字首和_POJ3179_Corral the Cows

題目概述: 計算包含C個點的正方形的最小邊長

思路分析:

    由於每個點的橫縱座標最大可能為10000, 題目記憶體限制為65536K, 如果申請一個int[10000][10000]那麼顯然直接記憶體超出限制, 考慮到至多給定500個點, 因此橫縱座標的各自最多有500個不同取值, 因此對橫縱座標分別離散化, 然後二分答案, 具體如下AC程式碼所示.

//POJ3179_Corral the Cows
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX = 5e2 + 5, NIL = 0x3f3f3f3f;
pair<int, int> p[MAX];//儲存輸入座標,first:x, second:y
int disx[MAX], disy[MAX], xlen, ylen, g[MAX][MAX], C, N;
//返回g[][]右上角頂點為(xmax, ymax), 左下角頂點為(xmin, ymin)的矩形區域的草數 
int getSum(int xmax, int ymax, int xmin, int ymin){
	return g[xmax][ymax] - g[xmin - 1][ymax] - g[xmax][ymin - 1] + g[xmin - 1][ymin - 1];
}
//如果存在邊長為len的正方形包含的草數不少於C則返回true, 否則返回false 
bool judge(int len){
	//列舉正方形右上角頂點
	for(int xmax = xlen, xmin, ymin; xmax >= 1; --xmax)
		for(int ymax = ylen; ymax >= 1; --ymax){
			xmin = lower_bound(disx + 1, disx + xmax + 1, disx[xmax] - len + 1) - disx; 
			ymin = lower_bound(disy + 1, disy + ymax + 1, disy[ymax] - len + 1) - disy;
			if(getSum(xmax, ymax, xmin, ymin) >= C) return true;
			if(ymin == 1) break;
		} 
	return false;
}
int main(){
	scanf("%d %d", &C, &N);
	for(int i = 1; i <= N; ++i) 
		scanf("%d %d", &p[i].first, &p[i].second), disx[i] = p[i].first, disy[i] = p[i].second;
	sort(disx + 1, disx + N + 1), xlen = unique(disx + 1, disx + N + 1) - (disx + 1);
	sort(disy + 1, disy + N + 1), ylen = unique(disy + 1, disy + N + 1) - (disy + 1);
	//下面初始化g[][]
	for(int i = 1, x, y; i <= N; ++i)
		x = lower_bound(disx + 1, disx + xlen + 1, p[i].first) - disx
		, y = lower_bound(disy + 1, disy + ylen + 1, p[i].second) - disy, ++g[x][y];
	//下面初始化g為其字首和
	for(int i = 1; i <= xlen; ++i)
		for(int j = 1; j <= ylen; ++j) g[i][j] = g[i][j] + g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1]; 
	int l = 1, r = max(disx[xlen], disy[ylen]), mid;
	while(mid = l + r >> 1, l < r) if(judge(mid)) r = mid; else l = mid + 1;
	cout << l << endl;
}