前提・実現したいこと
現在C#を勉強するにあたり、「一週間で身につくC#言語」サイトを参照しながら勉強しております。
一通り基礎編の練習問題を解き終えたので、チャレンジ問題に挑戦しているところです。
現在Prob8-2において、重複判定をどのように実装すればよいかわからない状態です。
Prob8-1
a,b,cを、いずれも1以上100以下の整数とするとき、a*a+b*b=c*cを満たす、全てのa,b,cの組み合わせ全てと、その数を求め、画面に表示しなさい。ただし、a,bの数値の組み合わせが同じものも別のものとしてもかまわない。具体的には、a=3,b=4,c=5と、a=4,b=3,c=5は別の組み合わせとする。Prob8-2←今ここを解いている
prob8-1.のデータから、重複を取り除いた組み合わせと、その数を表示するプログラムを作りなさい。具体的には、a=3,b=4,c=5と、a=4,b=3,c=5は同じものとみなす。
発生している問題・エラーメッセージ
重複する場合は表示させないという実装において、どのように実装すればよいのかわからない。
該当のソースコード
// prob8-1の解答
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem8_1
{
class Program
{
static void Main(string[] args)
{
int a, b, c;
for(a = 1; a <= 100; a++)
{
for(b = 1; b <= 100; b++)
{
for(c = 1; c <= 100; c++)
{
int x = a * a;
int y = b * b;
int z = c * c;
if(x + y == z)
{
Console.WriteLine("a = {0} b = {1} c = {2}", a, b, c);
}
}
}
}
}
}
}
// prob8-2の解答
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem8_2
{
class Program
{
static void Main(string[] args)
{
int a, b, c;
int m = 0;
int[,] ary = new int[1000, 3];
for(a = 1; a <= 100; a++)
{
for(b = 1; b <= 100; b++)
{
for(c = 1; c <= 100; c++)
{
int x = a * a;
int y = b * b;
int z = c * c;
if(x + y == z)
{
ary[m, 0] = a;
ary[m, 1] = b;
ary[m, 2] = c;
m++;
}
}
}
}
//Console.WriteLine("{0}", ary.Length);
for(int i = 0; i < ary.GetLength(0); i++)
{
if(ary[i, 0] != 0 && ary[i, 1] != 0 && ary[i, 2] != 0)
{
Console.WriteLine("a = {0} b = {1} c = {2}", ary[i, 0], ary[i, 1], ary[i, 2]);
}
}
}
}
}
試したこと
①Prob8-1を最初利用しようとしたが、重複を判定する場合は一度該当する数値をデータとして保持しないと無理ではないかと思い、二次元配列に該当数字をpush
②該当数字を配列に格納したが、数値0,0,0が出てきてしまうのでいったんif文にて0,0,0を非表示←この部分もなんとかしたい。
③重複判定を行おうとしたが、どのようにすれば良いのか手詰まりとなってしまっている状態
補足情報(言語/FW/ツール等のバージョンなど)
現在勉強中のため、お手数をおかけしてしまい申し訳ございませんが、わかりやすいアドバイスを頂けると幸いでございます。
またもし別の方法や簡単な方法等ございましたらそちらに関するアドバイスもありがたいです。
よろしくお願いいたします。
追記
回答より頂いたアドバイスを参照に作成
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Problem8_2
{
class Program
{
static void Main(string[] args)
{
int a, b, c;
int m = 0;
int[,] ary = new int[1000, 3];
for(a = 1; a <= 100; a++)
{
for(b = 1; b <= 100; b++)
{
for(c = 1; c <= 100; c++)
{
int x = a * a;
int y = b * b;
int z = c * c;
if(x + y == z)
{
// prob8-1より本制御文追加
if(a <= b)
{
Console.WriteLine("a = {0} b = {1} c = {2}", a, b, c);
}
}
}
}
}
//Console.WriteLine("{0}", ary.Length);
//for(int i = 0; i < ary.GetLength(0); i++)
//{
// if(ary[i, 0] != 0 && ary[i, 1] != 0 && ary[i, 2] != 0)
// {
// Console.WriteLine("a = {0} b = {1} c = {2}", ary[i, 0], ary[i, 1], ary[i, 2]);
// }
//}
}
}
}
ただなんとなく腑に落ちない部分があるので、頂いたアドバイスを参照にもう少し作ってみる
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
本件の場合重複しているかどうかはa,bの値のみのよって決まる(成立する組み合わせはa,bが決まればcは自ずと決まるので)と考えてよいと思います。さらにa,bを交換したものの重複を排除するなら最初からa <= bとなるような組み合わせについてのみチェックすることで重複排除そのものをしなくてよくなります。
(1) 問題文を読む限りは「望む結果が得られればよく、Prob8-1のアルゴリズムや結果のデータを利用する必要はない」と思います。
(2) 配列は一旦確保してしまうと、そこに有効なデータがあろうがなかろうが要素が存在してしまうので、「配列に格納されている有効な要素数」を別途変数で管理しないと「見てはいけない要素を見てしまう」結果になります。つまりfor(int i = 0; i < ary.GetLength(0); i++)
は適切なループの仕方ではありません。for(int i = 0; i < m; i++)
とするのが順当です。
なお、配列の多くの要素は多分無駄になりますし「1000要素で本当に大丈夫?」といった不安もあるのではないでしょうか?そんな場合は「可変長の列」を表現するクラスを使う方が素直に書けます。例えばListを用いれば次のように書けます。
var list = new List<int[]>();
...
if (x + y == z) {
list.add(new int[] { a, b, c };
}
...
for (int i = 0; i < list.Count; i++) {
...
}
(3) 最初に述べた方法にすればやる必要がなくなります。もし練習のために重複排除の論理を作るなら...
for (int i = 0; i < m; i++) {
bool found = false;
for (int j = 0; j < i; j++) {
if (i番目の解とj番目の解が重複している) {
found = true; // 重複解が見つかったことを覚える
break;
}
}
if (!bound) {
i番目の解を印字
}
}
(なお重複排除を行うために実際の応用プログラミングでまともにループで書くことは少ないと思います。Dictionaryなどのクラスに解を登録した上で「このデータって登録済みですか?」と問い合わせるメソッドを用いれば簡単に求まるからです。そのようなクラスをうまく使うには「登録する要素が等しいかどうかを比較できるクラスにする」といったより応用的な設計が必要になってきます。しかしながらプログラミングの練習をする上ではまず自前でループを書いて論理を考える練習をすることは価値があると思います。)
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
問題文にあるモノをコードで表現する。この場合、a, b, c を「ピタゴラス数」としてまとめことを考えるとよいです。
2つのピタゴラス数 p1 と p2 に対して、「同じか」がしりたいので、IComparable を実装してください。
あとは HashSet に詰めれば解決。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.23%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/06/27 15:50
可変長のListというものがあるんですね。その部分はまだ触ったことないので初めて知りました。
今回いただいたアドバイスを参照として、せこいですがProb8-1のif(x + y == z)の下にif(a <= b)を追加することで期待していた結果を得ることを確認できました。
ただこれだけだとなんか腑に落ちないというか、きちんと解いたという感じがしないので、頂いたアドバイスを参照にもう少し作りこんでいきたいと思います。
ご丁寧なアドバイスありがとうございました。