Aがn個,Bがm個存在するとき,それで構成されうる文字列を全て出力せよ.

具体例

例えばAが2個,Bが2個で構成される文字列は

AABB
ABAB
ABBA
BAAB
BABA
BBAA

の6通り.これらを出力するプログラムを考えろ.

出力アルゴリズム

普通に考えれば再帰的に出力するのが妥当だと思う.

#geshi(c++,number){{

#include <iostream>

#include <vector>

using namespace std;

ostream& operator << (ostream& outputStream, vector<char> output){

	vector<char>::iterator it;
	it	= output.begin();
	while(it != output.end()){
		outputStream << *it;
		it++;
	}
	outputStream << endl;
	return outputStream;

}

void recursivePermutation(vector<char> output, unsigned int nAlength, unsigned int nBlength){

	if(!(nAlength + nBlength)){
		// 残った文字数がゼロならば
		// 現状をdumpして返る
		cout << output;
	}else{
		if(nAlength > 0){
			// Aを当てはめてみる
			output.push_back('A');
			// 再帰呼び出し
			recursivePermutation(output, (--nAlength)++, nBlength);
			output.pop_back();
		}
		if(nBlength > 0){
			// Bを当てはめてみる
			output.push_back('B');
			// 再帰呼び出し
			recursivePermutation(output, nAlength, (--nBlength)++);
			output.pop_back();
		}
	}

}

int main(int argc, char **argv){

	unsigned int nALength, nBLength;
	// コマンドラインの引数をnAlength,nBlengthに代入する
	if(argc <= 2){
		//cerr << "Use as " << argv[0] << " A B " << endl;
		//return -1;
		// 引数ゼロの場合,デバッグ用にそれぞれ4を代入する
		nALength	= 4;
		nBLength	= 4;
	}else{
		nALength	= (unsigned int)atoi(argv[1]);
		nBLength	= (unsigned int)atoi(argv[2]);
	}
	vector<char> output;
	// 再帰関数呼び出し
	recursivePermutation(output, nALength, nBLength);
	return 0;

} }}

実行結果

$ ./a.out 2 2
AABB
ABAB
ABBA
BAAB
BABA
BBAA

改良版

#geshi(c++,number){{

#include <iostream>

#include <vector>

#include <numeric>

#include <cstdlib>

using namespace std;

ostream& operator << (ostream& outputStream, vector<char> output){

	vector<char>::iterator it;
	it	= output.begin();
	while(it != output.end()){
		outputStream << *it;
		it++;
	}
	outputStream << endl;
	return outputStream;

}

void recursivePermutation(vector<char> output, vector<unsigned int> lengths, int nTypeNumber){

	if(!accumulate(lengths.begin(),lengths.end(), 0)){
		// 残った文字数がゼロならば
		// 現状をdumpして返る 
		cout << output;
	}else{
		for(int i = 0;i < nTypeNumber;i++){
			if(lengths[i] > 0){
				// アルファベット順に当てはめ
				output.push_back('A' + i);
				lengths[i]--;
				// 再帰呼び出し
				recursivePermutation(output, lengths, nTypeNumber);
				lengths[i]++;
				output.pop_back();
			}
		}
	}

}

int main(int argc, char **argv){

	vector <unsigned int> lengths;
	int nTypeNumber;
	if(argc <= 2){
		// 引数ゼロの場合,デフォルトオプションとして4と
		// 文字種類=2種類を設定
		lengths.push_back(4);
		lengths.push_back(4);
		nTypeNumber	= 2;
	}else{
		for(int i = 0;i < argc-1;i++){
			lengths.push_back(atoi(argv[i+1]));
		}
		nTypeNumber	= argc - 1;
	}
	vector<char> output;
	// 再帰関数呼び出し
	recursivePermutation(output, lengths, nTypeNumber);
	return 0;

} }}

実行結果

$ ./a.out 2 2 2
AABBCC
AABCBC
AABCCB
AACBBC
AACBCB
AACCBB
ABABCC
ABACBC
ABACCB
ABBACC
ABBCAC
ABBCCA
ABCABC
ABCACB
ABCBAC
ABCBCA
ABCCAB
ABCCBA
ACABBC
ACABCB
ACACBB
ACBABC
ACBACB
ACBBAC
ACBBCA
ACBCAB
ACBCBA
ACCABB
ACCBAB
ACCBBA
BAABCC
BAACBC
BAACCB
BABACC
BABCAC
BABCCA
BACABC
BACACB
BACBAC
BACBCA
BACCAB
BACCBA
BBAACC
BBACAC
BBACCA
BBCAAC
BBCACA
BBCCAA
BCAABC
BCAACB
BCABAC
BCABCA
BCACAB
BCACBA
BCBAAC
BCBACA
BCBCAA
BCCAAB
BCCABA
BCCBAA
CAABBC
CAABCB
CAACBB
CABABC
CABACB
CABBAC
CABBCA
CABCAB
CABCBA
CACABB
CACBAB
CACBBA
CBAABC
CBAACB
CBABAC
CBABCA
CBACAB
CBACBA
CBBAAC
CBBACA
CBBCAA
CBCAAB
CBCABA
CBCBAA
CCAABB
CCABAB
CCABBA
CCBAAB
CCBABA
CCBBAA

改悪版?再帰的呼び出しを使わない方法

2種類の文字で順列数え上げの場合,できた文字列は2進数でユニークな数として表せる

文字列2進数10進数
AABB00113
BABA101010

ということは,文字列の長さLの配列を作り,2のL乗までカウントアップして行けば全部余すことなく調べられる


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-01-24 (月) 13:26:53