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

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

新規登録して質問してみよう
ただいま回答率
85.35%
アルゴリズム

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

Q&A

解決済

2回答

1114閲覧

整数を対称行列のindexと対応付ける方法

physics303

総合スコア89

アルゴリズム

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

0グッド

0クリップ

投稿2020/09/25 01:40

自分で実装してみたアルゴリズムがあるのですが,もっと良い方法があれば教えてほしいです.以下はC++で実装してますが,PythonやFortranでの回答でも構いません.

N×N の対称行列のインデックスを(i,j)と書きます.i<N, j<N です.
ここで,適当な整数の入力ele ( <= (N-1)(N+2)/2 ) に対して,対称行列のi <= j を満たすインデックス(i,j)を対応させます.

たとえば N = 4 で入力が ele=3 の場合は,

[0,,,*]

[1,2,,]
[3,4,5,*]
[6,7,8,9]

なので,出力は(2,0),同じく,N = 4 で ele = 8 ならば,出力は(3,2) といった具体です.

自分が実装したコードは以下です.高校数学の群数列のアイディアを思い出して,n行目の最小がn*(n+3)/2 - n で最大が n*(n+3)/2 であることを使ってみました.皆さんだったらどう実装しますか?

C++

1 2tuple<int, int> get_mtx_idx(int ele, int N){ 3 4 /* 5 * ele map to index (i, j) of symmetric matrix 6 * [[ 0, *, *, *, *, *, *] 7 * [ 1, 2, *, *, *, *, *] 8 * [ 3, 4, 5, *, *, *, *] 9 * [ 6, 7, 8, 9, *, *, *] 10 * [10,11,12,13,14, *, *] 11 * [15,16,17,18,19,20, *] 12 * [21,22,23,24,25,26,27] 13 * 14 * min in n-th row is n*(n+3)/2 - n 15 * max in n-th row is n*(n+3)/2 16 * 17 * */ 18 19 for (int n = 0 ; n <= N; n++){ 20 if ( n * ( n+3 ) /2 - n <= ele and ele <= n * ( n+3 ) /2 ){ 21 int i = n; 22 int j = ele - n * ( n+3 )/2 + n; 23 24 return{i, j}; 25 26 } 27 } 28 29}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

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

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

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

guest

回答2

0

ベストアンサー

こんにちは
Pythonを使いました。

python

1import math 2 3def get_mtx_idx(ele): 4 i = int(math.sqrt(2*ele+0.25) - 0.5) 5 j = ele - int(i*(i+1)/2) 6 return i, j

以下は上記を使った動作確認です。

python

1for ele in range(21): 2 print(f'{ele}: {get_mtx_idx(ele)}')

出力結果:

0: (0, 0)

1: (1, 0)
2: (1, 1)
3: (2, 0)
4: (2, 1)
5: (2, 2)
6: (3, 0)
7: (3, 1)
8: (3, 2)
9: (3, 3)
10: (4, 0)
11: (4, 1)
12: (4, 2)
13: (4, 3)
14: (4, 4)
15: (5, 0)
16: (5, 1)
17: (5, 2)
18: (5, 3)
19: (5, 4)
20: (5, 5)

以下で確認できます。

参考になれば幸いです。

追記

コメントからいただきました

ただ,もしよろしければ,int( math.sqrt( 2ele+0.25 ) - 0.5 ) がどこからやってきたか教えてもらうことは可能でしょうか?

に回答します。

なお、以下の説明で、プログラムのコードではなく数式の中では、乗算記号を省略します。また、i^2i の二乗を表すものとします。

まず、i (≧0)行目の先頭(0列目)の要素は、

i (i+1) / 2

です。たとえば、 i = 3 の行の先頭要素は、上記の式のiに3を代入した 3 (3 + 1) / 2 から得られる 6です。上記の先頭要素の式を使うと、与えられた ele が配置される行インデクスi は、以下の不等式

i (i+1) / 2 ≦ ele

を満たす最大の非負整数です。この不等式を変形して、左辺が i になるようにしていきます。まず、両辺を2倍し、左辺のカッコを展開します。

i^2 + i ≦ 2ele

両辺に 0.25 を加えて、

i^2 + i + 0.25 ≦ 2ele + 0.25

としておいて、左辺を因数分解すると

(i + 0.5)^2 ≦ 2ele + 0.25

となります。両辺の値は0より大きく、i + 0.5も0より大きいので、両辺の平方根をとると以下が得られます。

i + 0.5 ≦ √(2ele + 0.25)

左辺の 0.5 を右辺に移項すると、左辺がi の不等式

i ≦ √(2ele + 0.25) - 0.5

が得られました。これを満たす最大の非負整数が求めたいiになります。それは、右辺の値の小数部分を切り捨てれば得られますので、i を求める式をPythonで書くと

python

1i = int(math.sqrt(2*ele+0.25) - 0.5)

となります。i が得られると、列インデクスj は、ele と 行の先頭要素i (i+1) / 2 との差なので

python

1j = ele - int(i*(i+1)/2)

で得ることができます。

投稿2020/09/25 07:15

編集2020/09/26 07:00
jun68ykt

総合スコア9058

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

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

physics303

2020/09/25 07:57

ありがとうございます!! とてもシンプルで分かりやすいです! ただ,もしよろしければ,int( math.sqrt( 2ele+0.25 ) - 0.5 ) がどこからやってきたか教えてもらうことは可能でしょうか?
jun68ykt

2020/09/25 08:23

どういたしまして。 > int( math.sqrt( 2ele+0.25 ) - 0.5 ) の導き方を回答に追記しました。
physics303

2020/09/25 11:12

おおおお,大変よく分かりました!ありがとうございます!
guest

0

やってみたけど、アルゴリズムのキモは同じやね。
※ 時間計算量はO(√ele)

C++

1#include <iostream> 2#include <tuple> 3 4std::tuple<int, int> get_mtx_idx(int ele, int N){ 5 int delta = 0; 6 int sum = 0; 7 while ( ele >= sum ) { 8 sum += ++delta; 9 } 10 return { delta - 1, ele - sum + delta }; 11} 12 13// おためし 14int main() { 15 const int N = 4; 16 for ( int i = 0; i < 10; ++i ) { 17 auto idx = get_mtx_idx(i, 4); 18 std::cout << i << " (" << std::get<0>(idx) << ',' << std::get<1>(idx) << ")\n"; 19 } 20}

...あ、引数Nは要らんわ。

投稿2020/09/25 03:29

編集2020/09/25 07:42
episteme

総合スコア16612

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問