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

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

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

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio 2012

Microsoft Visual Studio 2012は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2010の次のバージョンです

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

C++

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

3回答

578閲覧

C++で重複配列を省くプログラム追加して作業効率を上げたいです。

i-am-programar

総合スコア7

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio 2012

Microsoft Visual Studio 2012は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2010の次のバージョンです

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

C++

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2017/11/30 20:16

###前提・実現したいこと
プログラミング言語C++でk*kのある配列を作ろうとしています。
まずkの要素は4つでそれぞれ1~12の値が入ります。kの4つの要素をそれぞれabcdとして
以下のような配列を作っています。そして0より値が小さくなった場合0と12を基準に巡回しています。例えば-2の場合9、-1の場合12です。
(a-a), a-b , a-c, a-d
b-a ,(b-b), b-c, b-d
c-a , c-b, (c-c), c-d
d-a , d-b , d-c, (d-d)
そして、この配列が対角線上になる0 ”()”で括っている部分を除く数が1回だけ出現しているか検査するプログラムをつくっています。
###発生している問題・エラーメッセージ
莫大な量の計算なので効率化を図りたいので、kの4つの要素が例えば(1,2,3,4)の時と
(1,2,4,3)や(2,1,4,3)の時などの重複配列は一緒なので配列を作る前に省きたいのですが、どのように省けばよいでしょうか?以下のプログラムコードを貼りますので改良のほうお願いします。
###該当のソースコード

C++

1#include <iostream> 2 3using namespace std; 4 5/** 6引数の配列をきれいに表示するやつ 7int* a -> 配列データの先頭アドレス 8int size -> 配列の大きさ 9*/ 10void drawSgArray(int* a, int size) { 11 for (int i = 0; i < size; i++) { 12 if (a[i] < 10) { cout << " " << a[i]; } 13 else { cout << a[i]; } 14 if (i < size - 1) cout << ","; 15 } 16 17 return; 18} 19 20/** 21引数の2次元配列をきれいに表示するやつ 22int** a -> 二次元配列データの先頭アドレス 23int low -> 行の大きさ 24int col -> 列の大きさ 25*/ 26void drawDwArray(int** a, int row, int col) { 27 for (int i = 0; i < col; i++) { 28 for (int j = 0; j < row; j++) { 29 if (a[i][j] < 10) { cout << " " << a[i][j]; } 30 else { cout << a[i][j]; } 31 if (j < row - 1) cout << ","; 32 } 33 cout << endl; 34 } 35 36 return; 37} 38 39/** 40巡回差行列になっているか。なっていたらtrueを返す。 41int** a -> 二次元配列の先頭アドレス 42int size -> 配列の長さ 43int max -> 最大値 44int imp -> 各値の表示回数 45*/ 46bool check(int** a, int size, int max, int imp) { 47 int* checker = new int[max + 1]; // 各値の表示回数を数えるやつ 48 49 // checkerの初期化 50 for (int i = 0; i < max + 1; i++) checker[i] = 0; 51 52 // 行列の各要素の値を見て、どの値が何回出ているのかをcheckerに記録 53 for (int i = 0; i < size; i++) { 54 for (int j = 0; j < size; j++) { 55 if (i != j) checker[a[i][j]]++; 56 } 57 } 58 59 // 数字の出る回数がおかしかったらfalse 60 for (int k = 1; k < max; k++) { 61 if (checker[k] != imp) return false; 62 } 63 64 // 何事もなかったらtrue 65 return true; 66} 67 68int main() { 69 // ============================================================================================ 70 // 初期設定 71 int cnt=0; //カウント 72 int matrixSize; // 行列の大きさ 73 int numberMax; // 最大値 74 int impression; // 出現回数 75 int isAll; // デバッグ 76 77 cout << "配列の大きさ:"; 78 cin >> matrixSize; 79 80 cout << "最大値:"; 81 cin >> numberMax; 82 83 cout << "出現回数:"; 84 cin >> impression; 85 86 cout << "すべての配列を出力する?(YES=1 / NO=0):"; 87 cin >> isAll; 88 89 // ============================================================================================ 90 // 間違い検知 91 if ((matrixSize * (matrixSize - 1)) % (numberMax - 1) != 0 || matrixSize <= 1) { 92 cout << "numberMaxの値、もしくはmatrixSizeの値を間違えて入力しています。" << endl; 93 cin.get(); 94 cin.get(); 95 return 0; 96 } 97 // ============================================================================================ 98 // 計測開始 99 int number[99] = {}; // 行列に代入する値を入れておく配列 100 for (;;) { 101 // 行列を表す二次元配列(matrix)の準備 102 int** matrix = new int*[matrixSize]; 103 for (int i = 0; i < matrixSize; i++) { 104 matrix[i] = new int[matrixSize]; 105 } 106 107 // 行列に値を代入 108 for (int i = 0; i < matrixSize; i++) { 109 for (int j = 0; j < matrixSize; j++) { 110 matrix[i][j] = number[i] - number[j]; 111 if (matrix[i][j] < 0) matrix[i][j] += numberMax; 112 } 113 } 114 115 116 // ============================================================================================ 117 // 巡回差行列になっているかのチェック 118 if (check(matrix, matrixSize, numberMax, impression) || isAll) { 119 // もしも巡回差行列になっていたらコンソールに表示(isAllが1なら無理やり表示) 120 cout << "========================" << endl; 121 cnt++; 122 // 代入した値をとりあえず書き出す 123 cout << "("; 124 drawSgArray(number, matrixSize); 125 cout << ")" << endl; 126 127 // 行列を書き出す 128 drawDwArray(matrix, matrixSize, matrixSize); 129 130 } 131 132 // ============================================================================================ 133 // 次の数字へ(2,3,0,1なら、3,3,0,1になる) 134 number[0]++; 135 for (int i = 0; i < matrixSize - 1; i++) { 136 if (number[i] >= numberMax) number[i + 1]++; 137 } 138 for (int i = 0; i < matrixSize - 1; i++) { 139 // 繰り上げが必要ならやっておく 140 if (number[i] >= numberMax) number[i] %= numberMax; 141 } 142 143 // ============================================================================================ 144 // メモリの開放 145 for (int i = 0; i < matrixSize; ++i) delete matrix[i]; 146 delete matrix; 147 148 // ============================================================================================ 149 // 最後まで計測できたのなら止める 150 if (number[matrixSize - 1] >= numberMax) break; 151 } 152 153 cin.get(); 154 cout<<"巡回差集合は"<<cnt/24<<"個あります。"<<endl; 155 cin.get(); 156 157 return 0; 158}

###試したこと
メモ化も試してみたのですが12121212個も配列を作ることが出来なかったので無理でした・・・
###補足情報(言語/FW/ツール等のバージョンなど)
統合開発環境はVisual studio 2012です

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

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

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

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

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

guest

回答3

0

順番と要素間での差しか影響しないので、

  • a=0に決め打つ
  • a<b<c<dとなるようなものだけ生成する

とすれば、生成数は大きく削減できます。

投稿2017/11/30 23:10

maisumakun

総合スコア145183

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

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

i-am-programar

2017/12/01 01:59

質問の前提で大きなミスがありました。このプログラムは4つの要素が1~12までのある特定(0を除く配列が1回ずつ出現する)条件をみたす4つの要素を全て何個あるか見つけるプログラムでした。a=0にすると必ず0を含む残り3つ要素がそれぞれ数値が入っているという事で合っているでしょうか?
guest

0

すごい愚直に回したコードが以下になります。
eSet.set.beginで戦闘のイテレータ取れるのでそのイテレータのvecの中身から自由に調理してください。

C++

1#include <iostream> 2#include <vector> 3#include <set> 4#include <algorithm> 5class QuadElem 6{ 7public: 8 QuadElem(); 9 ~QuadElem(); 10 bool operator==(const QuadElem& rhs) const; 11 bool operator<(const QuadElem& rhs)const; 12 void setArray(const int el1,const int el2,const int el3,const int el4); 13 std::vector<int> vec; 14 15private: 16}; 17 18QuadElem::QuadElem() 19{ 20 this->vec.resize(4); 21} 22 23QuadElem::~QuadElem() 24{ 25} 26bool QuadElem::operator==(const QuadElem & rhs) const 27{ 28 return this->vec == rhs.vec; 29} 30bool QuadElem::operator<(const QuadElem& rhs) const 31{ 32 int left, right; 33 left = this->vec[0] * 1000 + this->vec[1] * 100 + this->vec[2] * 10 + this->vec[3]; 34 right = rhs.vec[0] * 1000 + rhs.vec[1] * 100 + rhs.vec[2] * 10 + rhs.vec[3]; 35 return left<right; 36} 37void QuadElem::setArray(const int el0, const int el1, const int el2, const int el3) 38{ 39 this->vec[0] = el0; 40 this->vec[1] = el1; 41 this->vec[2] = el2; 42 this->vec[3] = el3; 43 std::sort(this->vec.begin(), this->vec.end()); 44} 45 46class ElemSet 47{ 48public: 49 ElemSet(); 50 ~ElemSet(); 51 bool insert(const QuadElem); 52 53 54private: 55 std::set<QuadElem> set; 56 57}; 58 59ElemSet::ElemSet() 60{ 61} 62 63ElemSet::~ElemSet() 64{ 65} 66 67bool ElemSet::insert(const QuadElem quadElem) 68{ 69 auto t =this->set.insert(quadElem); 70 return t.second; 71} 72 73int main(){ 74 QuadElem qE1, qE2, qE3, qE4; 75 ElemSet eSet; 76 for (size_t i = 1; i < 13; i++) 77 { 78 for (size_t j = 1; j < 13; j++) 79 { 80 for (size_t k = 1; k < 13; k++) 81 { 82 for (size_t l = 1; l < 13; l++) 83 { 84 qE1.setArray(i, j, k, l); 85 eSet.insert(qE1); 86 } 87 } 88 } 89 } 90 91 92}

投稿2017/12/01 05:50

m_yoko

総合スコア156

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

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

0

  • 1~K*(K-1) (= 1~12)の数値から相異なるK(=4)個を選ぶ。
  • 上記のK個の相異なる2つの差がすべて( =4!=12種類)異なる。

ものを選べばいけると思います。

a...dの制約条件がうまく決めきれませんでしたが
以下pythonコードで全探索と上記の手法とで結果が一致したので正しいと思います。

K=2で2個, K=3で12個, K=4で96個, K=5で240個

Python

1import itertools 2 3K = 4 # 正方行列 K * K 4NUM_CNT = K*(K-1) # 対角線以外を埋める数値の個数 5NUMS = [i+1 for i in range(NUM_CNT)] # a...nの走査範囲値 1...NUM_CNT (= K*(K-1) ) 6#NUMS = [i for i in range(NUM_CNT+1)] 7 8# 循環数を返す -1 = NUM_CNT, -2 = NUM_CNT-1, ... 9def circleNum( n): 10 if n < 0: 11 n += NUM_CNT+1 12 return n 13 14# 数値リストから行列を作成 15def getMat( nums): 16 return [[circleNum( nums[i]-nums[j]) for j in range(K)] for i in range(K)] 17 18# 重複判定 : 行列から 19def isMatDup( mat): 20 dup = set() 21 for i,j in itertools.product([k for k in range(K)], repeat=2): # 直積 22 if i != j: 23 if mat[i][j] in dup: 24 return True 25 dup.add(mat[i][j]) 26 return False 27 28# 重複判定 : 数値リストから 29def isNumDup( nums): 30 dup = set() 31 for n in itertools.permutations(nums, 2): # 順列 32 diff = circleNum(n[0] - n[1]) 33 if diff in dup: 34 return True 35 dup.add(diff) 36 return False 37 38 39# 計算 : 全探索+行列から判定 40def calc1( path): 41 print(path) 42 with open(path, 'w') as f: 43 dup = set() # 解(行列)の重複チェック用 44 lopCnt,dupCnt,okCnt = 0,0,0 45 for nums in itertools.product(NUMS, repeat=K): # 直積 46 mat = getMat( nums) 47 if not isMatDup(mat): 48 key = str(mat) 49 if key not in dup: 50 f.write( 'nums[%s] mat[%s]\n'%(nums,mat)) 51 okCnt += 1 52 dup.add(key) 53 else: 54 dupCnt += 1 55 lopCnt += 1 56 f.write( 'lop[%d] dup[%d] ok[%d]\n'%(lopCnt,dupCnt,okCnt)) 57 58 59# 計算 : 順列+数値リストから判定 60def calc2( path): 61 print(path) 62 with open(path, 'w') as f: 63 dup = set() # 解(行列)の重複チェック用 64 lopCnt,dupCnt,okCnt = 0,0,0 65 for nums in itertools.permutations(NUMS, K): # 順列 66 if not isNumDup(nums): 67 mat = getMat(nums) 68 key = str(mat) 69 if key not in dup: 70 f.write( 'nums[%s] mat[%s]\n'%(nums,mat)) 71 okCnt += 1 72 dup.add(key) 73 else: 74 dupCnt += 1 75 lopCnt += 1 76 f.write( 'lop[%d] dup[%d] ok[%d]\n'%(lopCnt,dupCnt,okCnt)) 77 78if __name__ == '__main__': 79 calc1('calc1.txt') 80 calc2('calc2.txt')

投稿2017/12/01 03:41

編集2017/12/01 08:46
can110

総合スコア38256

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問