スクールの課題です。
1、多次元配列の広さを入力
例:4 4
2、指定された広さ分の情報の入力
例:1
4 4
0010
1110
0010
0010
例:2
3 5
00010
11001
01100
3、1を囲うのに必要な棒が何本必要か計算して出力
例:1は14本
例:2は18本
現在の考え方
1を囲うのに4本必要 - 重なっている分(1つの場所で2本) = 必要な本数
例で考えると
(4×6)- (5×2)= 24 - 10 = 14
(4×6)- (3×2)= 24 - 6 = 18
で求められるとわかりました。
しかし、途中でどうやってプログラミングをすればいいのかわからなくなってしまいました。
ループの中で要素数が一致するのを数えようと思ったのですが…timelimit exceededになりました。
import
1 2 3public class Main { 4 5 public static void main(String[] args) { 6 Scanner sc = new Scanner(System.in); 7 8 int heigt = sc.nextInt(); //高さを取得 9 int width = sc.nextInt(); //幅を取得h); 10 11 //情報を1文字ずつ配列に格納していく 12 String[][] flower = new String[heigt][width]; 13 int count = 0; //#の数を数える 14 for (int i = 0; i < heigt; i++ ){ 15 String str = sc.next(); 16 for (int j = 0; j < width; j++ ){ 17 char[] arrayC = str.toCharArray(); //1文字ずつに変換 18 Character tmp = arrayC[j]; 19 flower[i][j] = tmp.toString(); 20 if("#".equals(flower[i][j])){ 21 //#の数を数える 22 count++; 23 } 24 } 25 } 26 System.out.println(count); 27 int count2 = 0; //#の縦の要素数が一緒がいくつあるか 28 int count3 = 0; //#が連続で続いているか 29 int[][] flg = new int[heigt][width]; //#があるか確認したら1にする 30 int idx = 0; 31 for (int i = 0; i < heigt; ){ 32 for (int j = 0; j < width; j++ ){ 33 if(flg[i][j] == 0 && "#".equals(flower[i][j])){ 34 //#の位置の要素数を保存 35 idx = j; 36 flg[i][j] = 1; 37 }else{ 38 //#がなければflgをあげる(確認済) 39 flg[i][j] = 1; 40 } 41 } 42 if(i > 0){ 43 for (int k = 0; k < width; k++ ){ 44 if("#".equals(flower[i][k]) && idx == k){ 45 //# かつ 前のと同じ位置の場合カウントする 46 count2++; 47 } 48 } 49 } 50 } 51 System.out.println(count2); 52 } 53} 54コード
間違っている点や
他の考え方など、ご教授いただければと思います。
よろしくお願いいたします。
なぜ 14 本と 18 本になるのかどうしてもわかりません。これは正しい答えですか?
棒を 2 で表すと、次のようになるのではないですか?
00020
02212
21112
02212
00212
00020
図のようであっていますが、角の部分が2本必要なので「2」の数と異なります。
111
021
上記のように「2」で表すと1つですが、実際の棒は「2」の上と右側に必要なので2つとして数えます。
わかりにくくて、すみませんがこの説明で理解できますでしょうか。
(説明不足なんですが)おそらく、縦と横を囲む棒を別に考えるのではないかと。
_|1
1 1
みたいに。って書いている間に補足があったわ。
問題2は、4行目が記述漏れの可能性がある。
なるほど。「棒」の意味がわかりました。
アルゴリズムとしては、まず 1 の数を数えてそれを 4 倍し、一つ一つの 1 を見て隣接する 1 の数を引けばいいと思います。多分質問に書いてあるのと同じですね。
この場合、
0010
1110
0010
0010
これをまず
000000
000100
011100
000100
000100
000000
このように変換すると、1 の隣に 1 か 0 があることが保証されるので、アルゴリズムが単純になると思います。その上で隣接した 1 の数を数えて次のように変換します。
000000
000100
012300
000200
000100
000000
そうすると引く数は 1 + 1 + 2 + 3 + 2 + 1 = 10 になるので、6 * 4 - 10 = 14 が出ます。
これでもいまいちよくわかりませんね。
000
010
000
これで周囲囲むのに4本いるというのはわかりましたが、
000
011
000
こうだとすると棒が共有されてるのは1本で7本必要になるのではないのですかね。
このように終端データを追加してアルゴリズムを単純化させる手法を「番兵」と言います。
https://ja.wikipedia.org/wiki/%E7%95%AA%E5%85%B5
例2は、重なってるのが4か所だと思いますが、なぜ3?
あ、例が、修正された。
yureighost さん、1 を囲む棒、つまり 1 の塊と外界を分けるボーダーだと思うので、1 と 1 の間に棒はないと思います。
Zuishinさん
あ、なるほど、1同士の間には棒はいらないってことですか。
「重なっている分」を引く みたいな変に工夫した(?)考え方をせずとも,
単純にカウントしていけばよい,すなわち,
「棒を置ける箇所すべてに関して,そこに棒を置くかどうかを判断すればいい」と考えたらどうですか.
行き着く結果(隣接要素の値が異なる箇所の個数を数えるだけの話になる)は一緒でしょうが,「考え方」として.)
回答3件
あなたの回答
tips
プレビュー