下の図のように4*4のマスに黒い■がいくつかあります。
例えば黒い■はいくつあるか数えるのだったら次のコードで求めることができます
Java
1 int [][]data = {{1,0,0,1},{1,0,0,0},{1,1,0,0},{0,1,0,1}}; 2 int count = 0; 3 for(int i = 0; i < 4; i++){ 4 for(int j = 0; j < 4; j++){ 5 if(data[i][j] == 1){ 6 count++; 7 } 8 } 9 } 10 System.out.println(count);
これはわかるのですが、問題は黒い■の塊の最大値です。上で使用した図だとMax = 5 と
なりますが、これを導く方法がいまいちわかりません。
(最終的には4*4のところを入力形式にして汎用的なものにするつもりですがその点は大丈夫です。)
今思いつくのは
つながっているところの面積をそれぞれ算出し、それらの最大値を求める。
どうやって、つながっているところの面積を出すのかがわかりません。
(ほかの方法があるのかもしれません。)
どなたかわかる方、ご教授お願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
mkgreiさんやswordoneさんがが示しているようにFlood fillを使うのだと思われます。
- 一つのマスから繋がっているマスを再帰で探しに行く。
- マスが見つかれば+1するか、再帰的にマスの数を足していくかの二通り。mkgreiさんの回答のリンク先は前者(たぶん)、後述のサンプルでは後者を採用している。
- ループしている場合があるので既に見たかの確認が必要。
- 左や上に戻る場合もあるので全方向について確認が必要。
- 分離された別の塊の存在もあるので、最終的には全マスについてチェック済みかの確認が必要。
- 全体の大きさの半分以上なら他のグループは探索しなくて良い。計算量としては半分になるだけなので、最悪時間も変わらないから、探索打ち切りしなくてもオーダーとしてはあまり影響しない(たぶん)。
- 計算量はO(n)かな?。nはマスの数(幅x高さ)。唐松模様だと4回見られるマスが増えるけど、余り影響しないはず。
実装サンプル。(Java10以上必須、Java9以下ではコンパイル不可)
Java
1import java.util.stream.IntStream; 2import java.util.Scanner; 3 4public class KatamariFloodFill { 5 public static void main(String ... args) { 6 final var sc = new Scanner(System.in); 7 final var width = sc.nextInt(); 8 final var height = sc.nextInt(); 9 final var list = new boolean[height + 2][width + 2]; 10 final var checked = new boolean[height + 2][width + 2]; 11 12 IntStream.rangeClosed(1, height).forEachOrdered(y -> { 13 IntStream.rangeClosed(1, width).forEachOrdered(x -> { 14 list[y][x] = sc.nextInt() == 1; 15 }); 16 }); 17 18 final var result = IntStream.rangeClosed(1, height).map(y -> 19 IntStream.rangeClosed(1, width).map(x -> 20 countConnectMasu(list, checked, x, y)).max().orElse(0) 21 ).max().orElse(0); 22 23 System.out.println(result); 24 } 25 26 static int countConnectMasu(boolean[][] list, boolean[][] checked, 27 int x, int y) { 28 if (!list[y][x] || checked[y][x]) return 0; 29 checked[y][x] = true; 30 return 1 + // self 31 countConnectMasu(list, checked, x - 1, y) + // left 32 countConnectMasu(list, checked, x, y - 1) + // up 33 countConnectMasu(list, checked, x + 1, y) + // right 34 countConnectMasu(list, checked, x, y + 1); // down 35 } 36}
なお、入力ファイルはこんな形を想定しています。
4 4 1 0 0 1 1 0 0 0 1 1 0 0 0 1 0 1
別の方法としては、マス毎にグループ番号を付けていくというのがあるのですが、グループが結合するときの処理が非常に面倒そうなので、あまりよくないかも。こちらも計算量はO(n)になるはず。
投稿2018/05/05 22:43
総合スコア21735
0
ベストアンサー
こちらのアルゴリズムを少しいじればほしい解が得られます。
javaではなく、Pythonですが。
python
1a = [[1,0,0,1,1,0], 2 [1,0,0,0,1,1], 3 [1,1,0,0,1,0], 4 [0,1,0,1,1,1]] 5from pprint import pprint 6pprint(a) 7 8def find(b, c, i, j, d=0): 9 if (i>=0 and i<len(b[0]) 10 and j>=0 and j<len(b) 11 and (c[j][i] is False) and b[j][i]==1): 12 d += 1 13 c[j][i] = True 14 d = find(b, c, i-1, j, d=d) 15 d = find(b, c, i+1, j, d=d) 16 d = find(b, c, i, j-1, d=d) 17 d = find(b, c, i, j+1, d=d) 18 return d 19 20def gen_bool(b): 21 c = [[False for _ in range(len(b[0]))] for _ in range(len(b))] 22 return c 23 24ans = 0 25c = gen_bool(a) 26for j in range(len(a)): 27 for i in range(len(a[0])): 28 if a[j][i]==1 and (c[j][i] is False): 29 d = find(a, c, i, j) 30 if d>ans: 31 ans = d 32print(ans)
投稿2018/05/05 14:44
編集2018/05/06 00:51総合スコア8560
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2018/05/06 03:01 編集
退会済みユーザー
2018/05/06 04:49 編集
0
"2d iland java find"
で google 検索すると、 (!, 1) の値の 2D マトリックスから 1 の塊の数を求めるという問題の java での対処例をたくさん見つけることができます。
これを変更して、見つけた島のそれぞれの面積をもとめるようにできると思います。
投稿2018/05/06 01:25
総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2018/05/06 02:58
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2018/05/06 02:56