AOJ 0542 認証レベル

以前まったく分からなかったが、久しぶりにやってみると解法がすぐ思いついて驚いた。

問題
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0542

解法
ある事務所で認証レベルを順番にあげていって、入れる部屋の総数とレベルの表をつくる
最初のサンプルでやってみると

5
2 2 1 2
9 5
1 17
3 2 2 1
6 1 20
8 18 3

1つ目の事務所について

レベル: 0  1  9 17
部屋 : 0  1  3  4

2つ目の事務所について

レベル: 0  1  6  8 18 20
部屋 : 0  1  2  3  5  6

とする。
あとは最初の事務所のレベルをあげていって、2つ目の事務所の部屋数を二分探索すればよい

#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
typedef pair<int, P> LP;
const int MAX_HW = 500;
int R, H[2], W[2], X[2], Y[2], office[2][MAX_HW][MAX_HW];
vector<int> room_n[2];
vector<int> level[2];
bool visited[2][MAX_HW][MAX_HW];
void init(int k){
	scanf("%d %d %d %d", &W[k], &H[k], &X[k], &Y[k]);
	room_n[k].clear();
	level[k].clear();
	X[k]--; Y[k]--;
	for(int i = 0; i < H[k]; i++)
		for(int j = 0; j < W[k]; j++){
			scanf("%d", &office[k][i][j]);
			visited[k][i][j] = false;
		}
}
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
int dfs(int k, int x, int y, int l, priority_queue<LP, vector<LP>, greater<LP> > &Q){
	visited[k][y][x] = true;
	int ret = 1;
	for(int i = 0; i < 4; i++){
		int nx = x + dx[i], ny = y + dy[i];
		if(0 <= nx && nx < W[k] && 0 <= ny && ny < H[k] && !visited[k][ny][nx]){
			if(office[k][ny][nx] <= l)
				ret += dfs(k, nx, ny, l, Q);
			else
				Q.push(LP(office[k][ny][nx], P(nx, ny)));
		}
	}
	return ret;
}
void make_table(int k){
	priority_queue<LP, vector<LP>, greater<LP> > Q;
	room_n[k].push_back(0);
	level[k].push_back(0);
	Q.push(LP(1, P(X[k], Y[k])));
	while(!Q.empty()){
		LP lp = Q.top(); Q.pop();
		int lev = lp.first, x = lp.second.first, y = lp.second.second;
		if(visited[k][y][x]) continue;
		room_n[k].push_back(dfs(k, x, y, lev, Q) + room_n[k][room_n[k].size() - 1]);
		level[k].push_back(lev);
	}
}
int main(){
	while(true){
		scanf("%d", &R);
		if(R == 0) return 0;
		init(0); init(1);
		make_table(0); make_table(1);
		int ans = 500000000;
		for(int i = 0; i < level[0].size(); i++){
			int r0 = room_n[0][i];
			int j = distance(room_n[1].begin(), lower_bound(room_n[1].begin(), room_n[1].end(), R - r0));
			if(j < room_n[1].size())
				ans = min(ans, level[0][i] + level[1][j]);
			}
		printf("%d\n", ans);
	}
	return 0;
}