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

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

新規登録して質問してみよう
ただいま回答率
85.48%
グラフ理論

グラフ理論とは、頂点(node)と辺(edge)で構成されたグラフに関する数学理論で、グラフの多様な性質を探求することを指します。グラフは、頂点と向き(矢印)を持つ辺で構成された有向グラフと、矢印のない無向グラフに分類。さまざまな日常の場面で使用することを目的としている理論です。

アルゴリズム

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

882閲覧

グラフを呼び出し、値を挿入する方法

退会済みユーザー

退会済みユーザー

総合スコア0

グラフ理論

グラフ理論とは、頂点(node)と辺(edge)で構成されたグラフに関する数学理論で、グラフの多様な性質を探求することを指します。グラフは、頂点と向き(矢印)を持つ辺で構成された有向グラフと、矢印のない無向グラフに分類。さまざまな日常の場面で使用することを目的としている理論です。

アルゴリズム

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/11/08 08:06

編集2021/11/10 00:14

実現したいこと

前回(https://teratail.com/questions/367958)からの質問になります。
ランダムに作成された接続行列から値を空の配列a[en]に値を挿入していき、
配列a[en]の全要素が1になるまでに挿入した回数を出力したいです
例)

頂点数(行) = 7 グラフの辺数(列) = 10 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 1 1 0 0 0 この行列から、a[en] = {1,1,1,1,1,1,1,1,1,1}となるまでに何回行の要素を組み合わせたか数えたい 0 1 0 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 1

該当するソースコード

C++

1#include <iostream> 2#include <vector> 3#include <algorithm> 4#include <list> 5#include <random> 6 7using namespace std; 8 9bool graph[1010][1010]; 10 11class con_matrix 12{ 13private: 14 vector < vector<int>> matrix; 15public: 16 con_matrix(int vn, int en) { set_vertex_num(vn, en); } 17 void set_vertex_num(int vn, int en) 18 { 19 matrix.resize(vn); //行列行数を設定 20 for (auto& line : matrix) 21 line.resize(en); //行列列数を設定 22 } 23 int get_vertex_num() const { return matrix.size(); } 24 int get_edge_num() const { return matrix.at(0).size(); } 25 26 void set_random(unsigned int seed = 0) // seed:乱数シード(値を変えると乱数列が変化) 27 { 28 for (auto& row : matrix) 29 { 30 for (auto& v : row) 31 v = 0; //要素をクリア 32 } 33 34 int vn = matrix.size(); //頂点数 35 int en = matrix.at(0).size(); //辺数 36 srand(seed); 37 vector<pair<int, int>> es; 38 for (int i = 0; i < vn - 1; ++i) 39 for (int j = i + 1; j < vn; ++j) 40 es.emplace_back(i, j); 41 for (int i = 0; i < en; ++i) 42 { 43 swap(es[i], es[i + rand() % (es.size() - i)]); 44 matrix[es[i].first][i] = 1; 45 matrix[es[i].second][i] = 1; 46 } 47 } 48 void disp_connection() const 49 { 50 for (auto& row : matrix) { 51 for (auto v : row) 52 cout << v << " "; //要素を表示 53 cout << endl; //行列列数を設定 54 } 55 } 56}; 57 58 59//最小の被覆数を探索する関数(接続行列) 60void is_covering(con_matrix &con) 61{ 62 int vn = con.get_vertex_num(); // 頂点数 63 int en = con.get_edge_num(); // 辺数 64 int min_c[5] = {}; // 使用した頂点数 65 int w = 0; // カウント 66 int* a = new int[en]; 67 a[en] = {}; 68 vector < vector<int>> matrix; 69 con.set_random(1); 70 71 for (int min = 0; min < 5; min++) { 72 while( w < en){ 73 w = 0; 74 int i = rand() % vn; 75 for (int j = 0; j < en; j++) { 76 if (a[j] == 0 && matrix[i][j] == 1) { 77 a[j] = 1; 78 } 79 } 80 for (int o = 0; o < en; o++) { 81 w = +a[o]; 82 min_c[min] = +1; 83 } 84 } 85 } 86 for (int b = 0; b < 5; b++) { 87 cout << min_c[b] << ","; 88 } 89} 90 91 92int main() 93{ 94 const int n = 7; //頂点数 95 double r = 0.5; //辺数の比率 96 const int e = ((n * (n - 1) / 2) * r); 97 vector<int> con; 98 int cover = 0; // 被覆数 99 con_matrix am(n, e); 100 am.set_random(1); //ランダムにグラフの接続行列を作る。引数は乱数シード 101 102 103 104 cout << "頂点数 = " << n << endl; 105 cout << "グラフの辺数 = " << e << endl; 106 am.disp_connection(); 107 cout << endl; 108 is_covering(am); 109 return 0; 110}

試したこと、エラー内容

エラーは出ず、実行はできているのですが、min_cの出力がされないです。

環境

Visual Studio 2019 C++です

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

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

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

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

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

fana

2021/11/08 09:09

> 以下の部分に書き足すことで実装できると思って書き込んでいます。 とか言われても,その is_covering の引数や戻り値が何なのかも不明だし, is_covering を呼び出す処理すらも無いみたいだから,一体どんな想定の上でこのメソッドを書いている途中なのか?等も他者には不明.
退会済みユーザー

退会済みユーザー

2021/11/08 09:23

参考としたプログラムから、自分なりに書き込んだものであったため、未完全な状態で投稿してしまいました。すみません。
fana

2021/11/08 09:45 編集

書き方が悪かったですかね. 不明 とは 説明する必要があるんじゃない? ということです. 例えば, 「is_covering の中身さえ完成すれば,それを使う側の処理の方は問題なくやれる」という想定であったとしたら, 「is_covering の引数は○○であり,このメソッドはこういう処理をして,戻り値として××を返す のだが,その実装ができない」とか述べれば何を解決すれば良いのかが明確になりますよね. 現状の質問文だと,「とにかくわからん」としか伝わらないので,読み手としても何が課題点なのかが判断できません. (「やりたいことはあるんだけど,コードは1文字も書けません」とか言われても困るわけで)
thkana

2021/11/08 22:46

「前回」とは? 調べりゃわかるだろ、と言わずにリンクを貼っておくのが気遣い/礼儀/常識というものです。 「エラー」とは? 「雑草という草はない」みたいな意味で、「エラー」とだけいうエラーはなく、なんらかの情報を持ったエラーメッセージが出たことをエラーと称しているはずです。つまり、エラーメッセージは「なにが問題であったか」が書かれた重要な情報です。当然あなたも精査したことと思いますが、なぜその重要な情報を質問で提示しないのでしょう?
fana

2021/11/09 01:06

> 出力された接続行列から、空の配列a[en]に1のみの列を挿入するようにしたい こういうのをもっとちゃんと(より具体的に,誰が読んでも意味がわかるように)書くべき. 「配列に 列を 挿入する」とはどのような操作なのか? 配列の要素の型とは何か? (「列」を突っ込めるならば要素は「列」なのか?) 「1のみの列」とはどういう意味か? (これでは「全要素の値が1であるような列」と読めてしまうが…?)
退会済みユーザー

退会済みユーザー

2021/11/09 02:22

質問のご指導、ありがとうございます。 とても勉強になります
fana

2021/11/09 02:56

> 初期化されていないメモリ'a'を使用しています って言われたなら,適切に初期化してみたらどうなんでしょう.
退会済みユーザー

退会済みユーザー

2021/11/09 02:59

その方法が分からないので、質問しています 参考となるものがあったら教えて欲しいです
fana

2021/11/09 03:10 編集

> int* a = new int[en]; 何か必要があって 要素数がen個の配列 を用意したんですよね. では,これを使い始める時点においては,各要素の値とはいくつであるべきなんですか? →この配列の値を見て何かをする処理を行うよりも前に,まずは適切な値を要素に突っ込んでおく必要がありますよね. ……っていうだけの話です. 参考とか何とかいうレベルの話ではなくて. 例えば,配列の最初の要素の値が7であって欲しいならば,7を代入しますよね. a[0] = 7; とか. 単にそんな話です. 全ての要素の値が5であってほしいならば for( int i=0; i<en; ++i )a[i]=5; とか何とかして,愚直に全要素に5を代入すればそれで目的を達することができるのではないですか?
guest

回答1

0

ベストアンサー

現質問文に対する直接的な回答 という感じではありませんが……


とりあえず con_matrix が持っている行列の値を外部から見る方法が設けられていない様子ですので, con_matrix に「ある頂点集合が頂点被覆か否かを調べる」というメソッドを追加することを考えてみます.
例えば…

C++

1class con_matrix 2{ 3 ... 4 5public: 6 //頂点集合がこの接続行列の頂点被覆であるか否かを調べる. 7 // 引数 Vtxs の要素は頂点のindex(この中に不正な値は入ってこない前提). 8 bool Is_Covering( const std::vector<int> &Vtxs ) const 9 { 10 if( Vtxs.empty() )return false; //引数が空ならとりあえず頂点被覆じゃない. 11 int nEdge = get_edge_num(); 12 for( int iEdge=0; iEdge<nEdge; ++iEdge )//全ての辺について 13 { //この辺が引数の頂点群によってカバーされているか?をチェック 14 bool IsEdgeCovered = false; 15 for( auto iVtx : Vtxs ) 16 { 17 if( matrix[iVtx][iEdge] ){ IsEdgeCovered=true; break; } 18 } 19 if( !IsEdgeCovered )return false; 20 } 21 return true; 22 } 23};

…みたいな.このコード例だと

配列a

というのは出てきていません.

おそらくはこのコード例みたいな「最も愚直なチェック」よりも何かしらの意味でマシな方法論を考えておられる(配列はその話の中で出てくる)のだろうと推測しますが,
それをすぐに実装できないのであれば,とりあえず今考えているその方法の実装は保留とし,このような「力業で効率悪そうだけどまずは動くんじゃない?」という代替実装を用意して,先に全体の処理フローを完成させる ことを行ってはどうでしょうか.

【効率が良い(?)チェック処理 と それを用いるフロー という複数個の要素を同時並行的に用意する】
のが厄介であれば,それよりも,
【「細部がとりあえず版だけども全体が動く状態」を一旦作ってから → その後で「とりあえず」部分をよりマシな実装に置き換える】
という手順にした方が,一度に相手にする要素が減るので楽になるのでは? という話です.



[追記]

The code example shown below finds the "minimum vertex cover" using the above method.
With this search process using queue, the "vertex cover" first found becomes (one of) the "minimum vertex cover".

C++

1//これは単に頂点群を表示するだけの作業関数 2inline void ShowVtxs( const std::vector<int> &Vtxs ) 3{ 4 std::cout << "{ "; 5 for( auto i : Vtxs ){ std::cout << i << " "; } 6 std::cout << "}"; 7} 8 9//探索処理用のデータ 10struct WorkData 11{ 12 std::vector< int > CurrVtxs; //頂点被覆か否かを調べる頂点集合 13 std::vector< int > RestVtxs; //CurrVtxが頂点被覆ではなかった場合にCurrVtxsに追加する頂点候補群 14}; 15 16int main(void) 17{ 18 //とりあえず接続行列があるとして… 19 con_matrix M; 20 21 //-------------------------- 22 //Queueを用いた幅優先探索 23 // 24 // 頂点個数が少ない側からチェックしていけば 25 // 最初に見つかった頂点被覆は最小頂点被覆(のひとつ)である 26 27 std::queue< WorkData > Queue; 28 {//Queueに探索処理のとっかかりとなるような最初のデータを入れる 29 WorkData WD; 30 {//最初のデータは{CurrVtxsが空で,RestVtxsが全ての頂点の集合}となるデータ 31 int n = M.get_vertex_num(); 32 WD.RestVtxs.resize(n); 33 for( int i=0; i<n; ++i )WD.RestVtxs[i] = i; 34 } 35 Queue.push( WD ); 36 } 37 38 while( !Queue.empty() ) 39 { 40 WorkData &WD = Queue.front(); 41 42 {//WDの中身を表示 43 std::cout << "Curr"; 44 ShowVtxs( WD.CurrVtxs ); 45 std::cout << " , Rest"; 46 ShowVtxs( WD.RestVtxs ); 47 std::cout << "\n"; 48 } 49 50 //WD.CurrVtxsが頂点被覆かどうかをチェック 51 if( M.Is_Covering( WD.CurrVtxs ) ) 52 { //頂点被覆が見つかったらその時点で探索終了 53 std::cout << " Found !!\n"; 54 break; 55 } 56 57 //WD.CurrVtxsが頂点被覆でなかった場合: 58 //{WD.RestVtxs内の頂点の1つをWD.CurrVtxs側に移した形のデータ}群 をQueueに入れる 59 for( auto i=WD.RestVtxs.begin(); i!=WD.RestVtxs.end(); ++i ) 60 { 61 WorkData NextPtn; 62 NextPtn.CurrVtxs = WD.CurrVtxs; 63 NextPtn.CurrVtxs.push_back( *i ); 64 NextPtn.RestVtxs.assign( i+1, WD.RestVtxs.end() ); //※以降の探索に重複パターンを作らないようにRestVtxsの中身を絞っておく 65 Queue.push( NextPtn ); 66 } 67 68 Queue.pop(); 69 } 70 71 std::cout << "END" << std::endl; 72 return 0; 73}

投稿2021/11/09 08:02

編集2021/11/10 01:51
fana

総合スコア11656

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

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

fana

2021/11/10 02:01 編集

「こんなんでいけるんじゃないだろうか?」と思う頂点被覆探索処理の実装を追記しておく. (特段の工夫も無い総当たり探索である) とりあえず質問に書かれている例: > 頂点数(行) = 7 > グラフの辺数(列) = 10 > 0 0 0 0 0 0 1 1 1 1 > 0 1 1 1 0 0 0 0 0 0 > 0 0 0 0 1 0 0 0 1 0 > 0 0 0 1 0 1 1 0 0 0 > 0 1 0 0 0 0 0 1 0 0 > 1 0 1 0 0 0 0 0 0 0 > 1 0 0 0 1 1 0 0 0 1 では,頂点群{0,1,6}で最小頂点被覆である,というそれらしい結果を生じた. (他のパターンでは試してない)
退会済みユーザー

退会済みユーザー

2021/11/10 15:30 編集

探索を途中で次の段に切り替えることは可能ですか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問