Problem:
C - Dowsing Machine / ダウジングマシーン
Story
世間ではXだとかYだとかで騒がしいけれど、これからの時代は"D"である。"パクリンモンスターD"は、秘密結社"R団"によって開発された"Dマシン"を使って"Dのひと"が財宝探索を行う大人気ゲームである。
このゲームでは、格子状マップのあるマスにいるDのひとが、隣接する上下左右のマスへの移動を繰り返し、財宝が存在するマスへの到達を目指す。 マップ上には財宝が存在するマスが1つだけある。 財宝が存在するマスは明らかにされていないため、Dマシンを使って存在する財宝のマスを絞り込んでから、財宝が存在するマスへ移動したい。
Dマシンを使うと、財宝が存在するマスを含む複数マスへの反応を示す。反応は、Dマシンを使ったときにDのひとが居たマスを基準に表現される。ただし、Dマシンは壊れていることがあり、Dマシンを使ったときに、財宝が存在し得ないマスへの反応を示すことがある。また、Dのひとが移動できない壁マスがマップ上に存在するため、財宝の存在するマスに移動できないこともある。DのひとはいろいろなマスでDマシンを使い、その反応を観測した。Dのひとは、財宝の存在するマスに到達できるだろうか。
Problem
高さ
h
幅
w
の二次元格子を考える。あるマス
t_{i,j}
は、次のいずれかの文字で表される。
"." : 通行可能であることを表す。このマスには財宝が存在するかもしれない。
"#" : 壁があり、通行不可能であることを表す。このマスには財宝は存在しない。
"D" : 通行可能であり、Dのひとがいることを表す。このマスには財宝が存在するかもしれない。
Dのひとは、上下左右に隣接する通行可能なマスへ移動することができる。
Dマシンは使用した位置に応じて、図のような二次元格子内のいずれかのマス集合への反応を示す。下図の各矩形は，それぞれが半径
r_1, r_2, ..., r_d
の正方形である。正方形の半径が
r_k
であるとは、正方形の一辺の長さが
2 r_k + 1
であることを意味する。
(x, y)
でDマシンを使用したときに示された反応を
s
とする。
1 \leq s \leq d-1
のときは、
(x, y)
を中心とする半径
r_{s+1}
の正方形から、 半径
r_s
の正方形を除いた図形に含まれるマスに財宝が存在することを表す。
s=0
のときは、
(x, y)
を中心とする半径
r_1
の正方形に含まれるマスに財宝が存在することを表す。
s=d
のときは、
(x, y)
を中心とする半径
r_d
の正方形の外側のマスに財宝が存在することを表す。財宝が存在するマスは必ず
1
つだけ存在する。しかし、Dマシンが壊れている場合、Dマシンはこれに矛盾した反応を示す。
Dマシンの使用によって示された反応が複数与えられる。 Dマシンが確実に壊れている場合は"Broken"、Dのひとがいる位置から財宝の存在するマスに必ずたどり着ける場合は"Yes"、絶対にたどり着けない場合は"No"、たどり着けるかどうか分からない場合は"Unknown"を出力せよ。
Input
入力は以下の形式で与えらえる。
h
w
d
n
t_{0,0}t_{0,1}...t_{0,w-1}
...
t_{h-1,0}t_{h-1,1}...t_{h-1,w-1}
r_1
r_2
...
r_d
x_1
y_1
s_1
...
x_n
y_n
s_n
1行目は4つの整数からなり，それぞれ，二次元格子の縦幅
h
、横幅
w
、 正方形の個数
d
、Dマシンを使用した回数
n
が空白1文字区切りで並んでいる。 続く
h
行では各マスの文字が与えられる。
i+2
行目(
0 \leq i < h
)の
j+1
番目(
0 \leq j < w
)の文字
t_{i,j}
はマス
(j,i)
の文字を表す。
h+2
行目では、各正方形の半径
r_k
(
1 \leq k \leq d
)が空白1文字区切りで与えられる。 続く
n
行では、Dマシンの反応が与えられる。
l+h+3
行目(
1 \leq l \leq n
)では、
x_l
、
y_l
、
s_l
が空白1文字区切りで与えられ、マス
(x_l, y_l)
でDマシンを使用したときに反応
s_l
が示されたことを表す。
制約
1 \leq h \leq 50, 1 \leq w \leq 50, 1 \leq d \leq 10, 1 \leq n \leq 50
t_{i,j}
は"#", ".", "D"のいずれかであり、文字"D"は必ず1つだけ存在する
0 \leq r_k \leq 50
であり，
k > 1
について
r_{k-1} < r_k
0 \leq x_l < w, 0 \leq y_l < h, 0 \leq s_l \leq d
文字"D"で表されるマスからの移動を繰り返すことで，マス
(x_l, y_l)
へ到達することができる
Output
"Broken", "Yes", "No", "Unknown"のいずれかのうち、適切なものを
1
行に出力せよ。行の最後では必ず改行を行うこと。
Sample Input 1
6 10 3 4
##########
#........#
#...D....#
#........#
#........#
##########
2 4 6
3 2 0
7 4 2
8 4 3
1 4 1
Sample Output 1
Yes
Sample Input 2
6 10 2 3
##########
#.#......#
###......#
#......D.#
#........#
##########
1 2
3 2 1
3 1 1
1 3 1
Sample Output 2
No
Sample Input 3
6 10 3 1
##########
#........#
#...D....#
#........#
#........#
##########
2 4 6
3 4 3
Sample Output 3
Broken
Sample Input 4
6 10 3 3
##########
#.#......#
###.D....#
#.#......#
#........#
##########
2 4 6
3 2 0
7 4 2
8 4 3
Sample Output 4
Unknown

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define fr first
#define sc second
#define pb push_back

typedef pair<int, int> Pii;

int h, w, d, n;
char mp[51][51];
int r[11];
int data[51][51] = {{0}};
int sx, sy;
int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0};

int bfs(int gy, int gx)
{
  bool used[51][51] = {{0}};
  queue<Pii> q;
  q.push(Pii(sy, sx));

  while ( !q.empty() ) {
    Pii p = q.front(); q.pop();
    int y = p.fr, x = p.sc;

    // cout << y << " " << x << endl;
    
    if ( y == gy && x == gx ) {
      return true;
    }

    if ( used[y][x] ) continue;
    used[y][x] = true;

    for ( int i = 0; i < 4; i++ ) {
      int ny = y + dy[i], nx = x + dx[i];
      if ( nx < 0 || ny < 0 || nx >= w || ny >= h || mp[ny][nx] == '#' ) continue;
      q.push(Pii(ny, nx));
    }
  }

  return false;
}

int main()
{
  cin >> h >> w >> d >> n;

  for ( int i = 0; i < h; i++ ) {
    for ( int j = 0; j < w; j++ ) {
      cin >> mp[i][j];
      if ( mp[i][j] == 'D' ) {
	sx = j;
	sy = i;
      }
    }
  }

  for ( int i = 0; i < d; i++ ) cin >> r[i];
  r[d] = 51;

  for ( int k = 0; k < n; k++ ) {
    int x, y, s;
    cin >> x >> y >> s;
    for ( int i = max(0, y - r[s]); i <= min(h-1, y + r[s]); i++ ) {
      for ( int j = max(0, x - r[s]); j <= min(w-1, x + r[s]); j++ ) {
	if ( s > 0 && (i >= y - r[s - 1] && j >= x - r[s - 1] && i <= y + r[s - 1] && j <= x + r[s - 1]) ) continue;
	data[i][j]++;
      }
    }
  }

  /*for ( int i = 0; i < h; i++ ) {
    for ( int j = 0; j < w; j++ ) {
      cout << data[i][j];
    }
    cout << endl;
    }*/

  vector<Pii> gl;
  for ( int i = 0; i < h; i++ ) {
    for ( int j = 0; j < w; j++ ) {
      if ( data[i][j] == n && mp[i][j] != '#' ) gl.pb(Pii(i, j));
    }
  }

  if ( gl.size() == 0 ) {
    cout << "Broken" << endl;
    return 0;
  }

  //cout << gl.size() << endl;
  int cnt = 0;
  for ( int i = 0; i < gl.size(); i++ ) {
    if ( bfs(gl[i].fr, gl[i].sc) ) cnt++;
  }

  if ( cnt == gl.size() ) cout << "Yes" << endl;
  else if ( cnt == 0 ) cout << "No" << endl;
  else cout << "Unknown" << endl;

  return 0;  
}
accuracy: 1
time_ms: 40
memory_kb: 3184
final_rank: 3

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;

const int MAX = 100;
typedef pair<int,int> ii;
int h,w,n,q,sx,sy,gx,gy;
char c[MAX][MAX];
int r[MAX],field[MAX][MAX];
bool visited[MAX][MAX];
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};

bool dfs(int x,int y){
  if( x == gx && y == gy ) return true;
  rep(i,4){
    int nx = x + dx[i], ny = y + dy[i];
    if( !( 0 <= nx && nx < w && 0 <= ny && ny < h ) ) continue;
    if( c[ny][nx] == '#' ) continue;
    if( !visited[ny][nx] ) {
      visited[ny][nx] = true;
      if( dfs(nx,ny) ) return true;
    }
  }
  return false;
}

void draw(int x,int y,int index){
  rep(i,h) rep(j,w) if( c[i][j] == '.' ) {
    if( index == n ) {
      if( abs(j-x) <= r[index-1] && abs(i-y) <= r[index-1] ) continue;
      ++field[i][j];
    } else {
      if( !( abs(j-x) <= r[index] && abs(i-y) <= r[index] ) ) continue;
      ++field[i][j];
    }
  }
  if( !index || index == n ) return;
    rep(i,h) rep(j,w) if( c[i][j] == '.' ) {
      if( !( abs(j-x) <= r[index-1] && abs(i-y) <= r[index-1] ) ) continue;
      --field[i][j];
  }
}

int main(){
  cin >> h >> w >> n >> q;
  rep(i,h) {
    string s;
    cin >> s;
    rep(j,w) {
      c[i][j] = s[j];
      if( s[j] == 'D' ) { sx = j, sy = i; c[i][j] = '.'; }
    }
  }
  rep(i,n) cin >> r[i];
  rep(_,q){
    int x,y,s;
    cin >> x >> y >> s;
    draw(x,y,s);
  }
  /*
  rep(i,h) {
    rep(j,w){
      cout << field[i][j] << " ";
    } puts("");
  }
  */
  int cnt = 0;
  vector<ii> vec;
  rep(i,h) rep(j,w) if( field[i][j] == q ) { ++cnt; vec.push_back(ii(j,i)); }
  if( cnt == 0 ) puts("Broken");
  else {
    cnt = 0;
    rep(i,vec.size()){
      memset(visited,false,sizeof(visited));
      visited[sy][sx] = true;
      gx = vec[i].first, gy = vec[i].second;
      if( dfs(sx,sy) ) ++cnt;
    }
    if( cnt == vec.size() ) puts("Yes");
    else if( cnt == 0 ) puts("No");
    else puts("Unknown");
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1316
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;

constexpr int MAX_SIZE = 50;
constexpr int MAX_D = 10;
constexpr int dx[4] = {1, -1, 0, 0};
constexpr int dy[4] = {0, 0, 1, -1};

typedef pair<int, int> point;

int h, w, d, n;
string field[MAX_SIZE];
int r[MAX_D];
bool visited[MAX_SIZE][MAX_SIZE];

set<point> get_area() {
	int x, y, s;
	cin >> x >> y >> s;

	int lower, upper;
	if(s == 0) {
		lower = -1;
		upper = r[0];
	}
	else if(s == d) {
		lower = r[d - 1];
		upper = INT_MAX;
	}
	else {
		lower = r[s - 1];
		upper = r[s];
	}

	set<point> res;
	for(int i = 0; i < h; ++i) {
		for(int j = 0; j < w; ++j) {
			const int len = max(abs(y - i), abs(x - j));
			if(len <= lower || len > upper) continue;
			if(field[i][j] == '#') continue;
			res.insert({j, i});
		}
	}
	return res;
}

template<class T>
set<T> intersect(const set<T> &a, const set<T> &b) {
	set<T> res;
	for(const auto &e : a) {
		if(b.count(e)) res.insert(e);
	}
	return res;
}

bool out(int x, int y) {
	return x < 0 || y < 0 || x >= w || y >= h;
}

void bfs(int sx, int sy) {
	memset(visited, false, sizeof(visited));
	visited[sy][sx] = true;
	queue<point> que;
	que.push({sx, sy});

	while(!que.empty()) {
		const int x = que.front().first;
		const int y = que.front().second;
		que.pop();

		for(int d = 0; d < 4; ++d) {
			const int nx = x + dx[d];
			const int ny = y + dy[d];
			if(out(nx, ny)) continue;
			if(field[ny][nx] == '#') continue;

			if(!visited[ny][nx]) {
				que.push({nx, ny});
				visited[ny][nx] = true;
			}
		}
	}
}

int main() {
	cin >> h >> w >> d >> n;

	int sx, sy;
	for(int i = 0; i < h; ++i) {
		cin >> field[i];
		int pos;
		if((pos = field[i].find('D')) != string::npos) {
			sx = pos;
			sy = i;
		}
	}

	for(int i = 0; i < d; ++i) {
		cin >> r[i];
	}

	auto common_area = get_area();
	for(int i = 1; i < n; ++i) {
		common_area = intersect(common_area, get_area());
	}

	if(common_area.size() == 0) {
		cout << "Broken" << endl;
		return 0;
	}

	bfs(sx, sy);

	int cnt = 0;
	for(const auto g : common_area) {
		if(visited[g.second][g.first]) ++cnt;
	}
	if(cnt == 0) {
		cout << "No" << endl;
	}
	else if(cnt == common_area.size()) {
		cout << "Yes" << endl;
	}
	else {
		cout << "Unknown" << endl;
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1472
final_rank: 2