質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

4回答

1215閲覧

塊の面積の最大値を求めたいです。

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

0クリップ

投稿2018/05/05 13:03

下の図のように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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/06 02:56

回答ありがとうございます。 「•全体の大きさの半分以上なら他のグループは探索しなくて良い。」という考え方が重要だと 感じました。
guest

0

単純に考えるなら、
■があったら、その周辺の■を探し、その■の周辺の■を探し…とやっていく方法が挙げられます。
また、そのマスを一度見たかをチェックするbooleanの配列も必要でしょうか。
再帰で定義すると比較的楽かと思います。

投稿2018/05/05 15:07

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/06 02:56

回答ありがとうございます。「再帰」で解く方法が勉強になりました。
guest

0

ベストアンサー

https://tekmarathon.com/2012/10/04/find-length-of-connected-cells-of-1ssector-in-an-matrix-of-0s-and-1s/

こちらのアルゴリズムを少しいじればほしい解が得られます。


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
mkgrei

総合スコア8560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/06 03:01 編集

回答ありがとうございました。pythonは最近勉強したばかりですが頑張って読んで Javaで書こうと思います。
退会済みユーザー

退会済みユーザー

2018/05/06 04:49 編集

無事、Javaに移植することができました。ありがとうございました。
guest

0

"2d iland java find"
で google 検索すると、 (!, 1) の値の 2D マトリックスから 1 の塊の数を求めるという問題の java での対処例をたくさん見つけることができます。

これを変更して、見つけた島のそれぞれの面積をもとめるようにできると思います。

投稿2018/05/06 01:25

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/05/06 02:58

回答ありがとうございます。"2d iland java find"で検索したら関連した問題がいくつか出たので それを参考にしたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問