結果
| 問題 |
No.348 カゴメカゴメ
|
| コンテスト | |
| ユーザー |
moti
|
| 提出日時 | 2016-03-24 03:16:16 |
| 言語 | C++11(廃止可能性あり) (gcc 13.3.0) |
| 結果 |
AC
|
| 実行時間 | 44 ms / 2,000 ms |
| コード長 | 3,503 bytes |
| コンパイル時間 | 1,640 ms |
| コンパイル使用メモリ | 180,908 KB |
| 実行使用メモリ | 9,588 KB |
| 最終ジャッジ日時 | 2024-10-01 21:47:42 |
| 合計ジャッジ時間 | 3,931 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 53 |
コンパイルメッセージ
main.cpp: In function ‘int main()’:
main.cpp:116:8: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
116 | scanf("%d %d", &N, &M);
| ~~~~~^~~~~~~~~~~~~~~~~
main.cpp:121:10: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
121 | scanf("%s", G[i]+1);
| ~~~~~^~~~~~~~~~~~~~
ソースコード
// 入力をscanfにしたときの速度差テスト用
#include <bits/stdc++.h>
using namespace std;
#define REP(i,a,b) for(int i=a;i<(int)b;i++)
#define rep(i,n) REP(i,0,n)
#define minus(c) memset(c, -1, sizeof c)
const int Max = 110890;
int dx[] = {-1,0,1,0,-1,1,1,-1};
int dy[] = {0,-1,0,1,-1,-1,1,1};
char VisMark = ' ';
char RingMark = 'o';
int N, M;
char G[1010][1010];
int ring_lens[Max];
vector<int> tree[Max]; // to, cost
template<class T> constexpr bool in_range(T y, T x, T H, T W) { return 0<=y&&y<H&&0<=x&&x<W; }
void make_tree() {
auto get_ring_len = [](int sy, int sx) {
int ret = 1;
queue<pair<int, int>> q;
q.emplace(sy, sx);
G[sy][sx] = RingMark;
while(!q.empty()) {
int y, x; tie(y, x) = q.front(); q.pop();
rep(i, 8) { // 'x'は8方向
int ny = y + dy[i], nx = x + dx[i];
if(!in_range(ny, nx, N, M)) { continue; }
if(G[ny][nx] != 'x') { continue; }
G[ny][nx] = RingMark;
ret ++;
q.emplace(ny, nx);
}
}
return ret;
};
auto get_next_depth_ring = [&](int sy, int sx) {
vector<tuple<int, int, int>> ret;
queue<pair<int, int>> q;
q.emplace(sy, sx);
G[sy][sx] = VisMark;
// 次の深さの輪を見つけるために、同じ深さ輪の間の '.' を訪れるBFS
while(!q.empty()) {
int y, x; tie(y, x) = q.front(); q.pop();
rep(i, 4) { // 4方向で輪を跨がずに'.'を消す
int ny = y + dy[i], nx = x + dx[i];
if(!in_range(ny, nx, N, M)) { continue; }
// 同じ深さの輪の間の '.'
if(G[ny][nx] == '.') {
G[ny][nx] = VisMark;
q.emplace(ny, nx);
}
// 'x' は輪の要素なので、一つ見つけてあとは塗りつぶす
if(G[ny][nx] == 'x') {
ret.emplace_back(ny, nx, get_ring_len(ny, nx));
}
}
}
return std::move(ret);
};
// 同じ深さの木の葉が左から並ぶ (y, x, ノード番号)
// '.'が連続する領域をノードと捉える
queue<tuple<int, int, int>> leaves;
leaves.emplace(0, 0, 0);
int nextch = 1;
// BFS木を作る
while(!leaves.empty()) {
int ly, lx, leaf; tie(ly, lx, leaf) = leaves.front(); leaves.pop();
auto ring_nodes = get_next_depth_ring(ly, lx);
for(auto && e: ring_nodes) {
int y, x, len; tie(y, x, len) = e;
tree[leaf].emplace_back(nextch);
ring_lens[nextch] = len;
rep(k, 8) { // 8方向で輪を跨ぐ'.'を見つける
int ny = y + dy[k], nx = x + dx[k];
if(!in_range(ny, nx, N, M)) { continue; }
if(G[ny][nx] == '.') {
leaves.emplace(ny, nx, nextch);
break;
}
}
nextch++;
}
}
}
int dp[Max][2];
int rec(int curr, bool par_used = true) {
auto& ret = dp[curr][par_used];
if(ret + 1) { return ret; }
if(tree[curr].empty()) { return ret = par_used ? 0 : ring_lens[curr]; }
ret = 0;
if(par_used) {
rep(i, tree[curr].size()) { ret += rec(tree[curr][i], false); }
}
else {
int r1 = ring_lens[curr];
for(auto && e: tree[curr]) { r1 += rec(e, true); }
int r2 = 0;
for(auto && e: tree[curr]) { r2 += rec(e, false); }
ret = max(r1, r2);
}
return ret;
}
int main() {
scanf("%d %d", &N, &M);
N += 2, M += 2;
rep(i, M) G[0][i] = '.';
REP(i, 1, N-1) {
G[i][0] = '.';
scanf("%s", G[i]+1);
G[i][M-1] = '.';
}
rep(i, M) G[N-1][i] = '.';
make_tree();
minus(dp);
cout << rec(0) << endl;
return 0;
}
moti