- // 小町算
- // 2020/06/18-2020/06/20
- #include <iostream>
- #include <sstream> // string stream を用いるので
- #include <fstream> // ファイルを用いるので
- #include <queue> // que 使用
- #ifdef __GNUC__
- #include <climits> //mingw で必要 INT_MAX
- #endif
- using namespace std;
-
- // 有理数(分数)クラスの定義
- class RATIONAL{
- int xi, yi; // private
- public:
- RATIONAL(int a=0,int b=1){xi=a;yi=b;}; // コンストラクタ 分母yiの既定値は1
- int numerator(){ return xi; }; // 分子
- int denominator(){ return yi; }; // 分母
- RATIONAL operator +(RATIONAL a);
- RATIONAL operator -(RATIONAL a);
- RATIONAL operator *(RATIONAL a);
- RATIONAL operator /(RATIONAL a);
- int operator ==(RATIONAL a);
- int operator !=(RATIONAL a);
- int operator >(RATIONAL a);
- int operator >=(RATIONAL a);
- int operator <(RATIONAL a);
- int operator <=(RATIONAL a);
- friend ostream& operator << ( ostream &os, RATIONAL &a );
- friend istream& operator >> ( istream &os, RATIONAL &a );
- };
- const RATIONAL RATIONAL_ZERO(0,1);
- const RATIONAL RATIONAL_INF=INT_MAX;
-
- // 有理数演算の実装
- RATIONAL RATIONAL :: operator +(RATIONAL a){
- RATIONAL b(xi * a.yi + yi * a.xi, yi * a.yi );
- return b;
- }
- RATIONAL RATIONAL :: operator -(RATIONAL a){
- RATIONAL b(xi * a.yi - yi * a.xi, yi * a.yi );
- return b;
- }
- RATIONAL RATIONAL :: operator *(RATIONAL a){
- RATIONAL b(xi * a.xi, yi * a.yi );
- return b;
- }
- RATIONAL RATIONAL :: operator /(RATIONAL a){
- RATIONAL b(xi * a.yi, yi * a.xi );
- return b;
- }
- int RATIONAL :: operator ==(RATIONAL a){
- if( (xi*a.yi) == (yi*a.xi) ) return 1;
- return 0;
- }
- int RATIONAL :: operator !=(RATIONAL a){
- return !((xi*a.yi) == (yi*a.xi));
- }
- int RATIONAL :: operator >(RATIONAL a){
- return ( (xi*a.yi-yi*a.xi) * (yi*a.yi) > 0 );
- }
- int RATIONAL :: operator <(RATIONAL a){
- return ( (xi*a.yi-yi*a.xi) * (yi*a.yi) < 0 );// 分母分子が同符号
- }
- int RATIONAL :: operator >=(RATIONAL a){
- return !(RATIONAL(xi,yi) < a);
- }
- int RATIONAL :: operator <=(RATIONAL a){
- return !(RATIONAL(xi,yi) > a);
- }
- // 入出力
- ostream& operator << (ostream &os, RATIONAL &a){
- if( a.yi == 1 ) os << a.xi;
- else os << a.xi << "/" << a.yi;
- return os;
- }
- istream& operator >> (istream &is, RATIONAL &a){
- is >> a.xi >> a.yi;
- return is;
- }
- // ユークリッドの互除法による有理数の既約化
- RATIONAL Euclidean_Algorithm( RATIONAL ra ){
- int a = ra.numerator(), b = ra.denominator();
- int a0 = a, b0 = b;
- int mod = a % b;
- while( mod ){
- a = b;
- b = mod;
- mod = a%b;
- }
- RATIONAL rra( a0/b, b0/b );// lcd 最大公約数 b で約分
- return rra;
- }
- //##### 有理数クラス宣言はここまで #####
-
- RATIONAL g_TARGETr = RATIONAL(100,1);// (1,17); 演算結果として目指す数
- RATIONAL g_nr[9] = {1,2,3,4,5,6,7,8,9};// default 123456789
-
- ofstream ofs("小町算解答.txt",ios::app);// ファイル追加モードで開く
-
- void GetNumbers();
- // 式の計算を行い100になるかどうかをチェック
- int Check100( char op[8] );
-
- // -----------------------------------
- // ##### main #####
- // -----------------------------------
- int main( void )
- {
- // TARGETr と 9桁の数字を入力させる
- GetNumbers();
-
- // 計算式が格納される 例えば 1+2#3+4+5+6+7#8*9
- char op[5] = {'+','-','*','/','#'};// # は空白無し つまり 1#2 は 12 を表す
- char Operator[8];
- int i=0; // 全処理候補数=390625=5^8
- int noi=0; // 答えの数
- // 可能な計算式を全て求める
- for(int i0=0;i0<5;i0++){
- Operator[0]=op[i0]; // 1 と 2 の間に入る記号 +-*/#
- for(int i1=0;i1<5;i1++){
- Operator[1]=op[i1]; // 2 3 間 +-*/#
- for(int i2=0;i2<5;i2++){
- Operator[2]=op[i2]; // 3 4 間 +-*/#
- for(int i3=0;i3<5;i3++){
- Operator[3]=op[i3]; // 4 5 間 +-*/#
- for(int i4=0;i4<5;i4++){
- Operator[4]=op[i4]; // 5 6 間 +-*/#
- for(int i5=0;i5<5;i5++){
- Operator[5]=op[i5]; // 6 7 間 +-*/#
- for(int i6=0;i6<5;i6++){
- Operator[6]=op[i6]; // 7 8 間 +-*/#
- for(int i7=0;i7<5;i7++){
- Operator[7]=op[i7]; // 8 9 間 +-*/#
- i ++;
- if( Check100( Operator ) ){// 検算 100?
- noi++;// 候補数を増やす
- }
- }
- }
- }
- }
- }
- }
- }
- }
- ofs << "\t\t" << g_TARGETr << endl;
- ofs << "\t\t(" << noi << ")/(" << i << ")" << endl;
- ofs.close(); // ファイルを閉じる
- cout << g_TARGETr << endl;
- cout << "(" << noi << ")/(" << i << ")" << endl;
- return noi;
- }
- // ---------------------------------------------
- // Check100
- // ---------------------------------------------
- int Check100( char op[8] ){
- ostringstream osstrm;
- deque<RATIONAL> Rdq0; // 両終端キュー double-ended queue
- for(int i=0;i<9;i++){
- Rdq0.push_back( g_nr[i] ); // 順にqueに格納
- }
-
- deque<RATIONAL> Rdq; // 両終端キュー double-ended queue
- deque<char> Opdq; // 両終端キュー double-ended queue
-
- RATIONAL Rtmp0, Rtmp1, Rtmp2;
- // 前処理 # 演算子の場合
- for(int i=0; i<8; i++){
- if(op[i]=='#'){ // 前後の数字を纏める preprocess
- Rtmp1 = Rdq0.front(); Rdq0.pop_front();
- Rtmp2 = Rdq0.front(); Rdq0.pop_front();
- Rtmp0 = Rtmp1*10 + Rtmp2; // 例えば 1#2#3 -> 12#3 -> 123 とする
- Rdq0.push_front( Rtmp0 ); // 元の場所に戻す
- }else{ // 加減乗除はそのままpush
- Rtmp1 = Rdq0.front();
- Rdq.push_back( Rtmp1 ); // 登録
- Opdq.push_back( op[i] ); // 登録
- Rdq0.pop_front(); // 取り去る
- }
- }
- Rdq.push_back(Rdq0.front()); // 登録
- Rdq0.pop_front(); // 取り去る
- // ここまででque セット
-
- deque<RATIONAL> Rdq1; // 両終端キュー double-ended queue
- deque<char> Opdq1; // 両終端キュー double-ended queue
- RATIONAL R1,R2,R3;
- while( !Opdq.empty() ){ // */の処理
- switch(Opdq.front()){
- case '*' :
- R1 = Rdq.front(); Rdq.pop_front();
- R2 = Rdq.front(); Rdq.pop_front();
- R3 = R1*R2;
- Rdq.push_front(R3); //登録
- break;
- case '/' :
- R1 = Rdq.front(); Rdq.pop_front();
- R2 = Rdq.front(); Rdq.pop_front();
- R3 = R1/R2;
- Rdq.push_front( R3 ); //登録
- break;
- default :
- Rdq1.push_back(Rdq.front());Rdq.pop_front();
- Opdq1.push_back(Opdq.front()); //登録
- break;
- }
- Opdq.pop_front();
- }
- Rdq1.push_back( Rdq.front() ); Rdq.pop_front();
- while( !Opdq1.empty() ){// +−の処理
- switch( Opdq1.front() ){
- case '+' :
- R1 = Rdq1.front(); Rdq1.pop_front();
- R2 = Rdq1.front(); Rdq1.pop_front();
- R3 = R1+R2;
- Rdq1.push_front( R3 ); // 登録
- break;
- case '-' :
- R1 = Rdq1.front(); Rdq1.pop_front();
- R2 = Rdq1.front(); Rdq1.pop_front();
- R3 = R1-R2;
- Rdq1.push_front( R3 ); // 登録
- break;
- default : break;
- }
- Opdq1.pop_front();
- }
- R1 = Euclidean_Algorithm(Rdq1.front());Rdq1.pop_front();// 既約分数へ
- if( R1 == g_TARGETr ){
- for( int j=0;j<8;j++){
- osstrm << g_nr[j];
- if( op[j] != '#' )osstrm<<op[j];// #文字は数字を連結
- }osstrm<<g_nr[8]<<endl;
- ofs << osstrm.str(); // ファイルに書き出す
- osstrm.str(""); // buffa clear
- return 1;
- }
- return 0;
- }
- //---------------
- void GetNumbers()
- {
- char na[16];
- cout << "標的の数(有理数)は(100)? 100 1 ";
- cin >> g_TARGETr; cin.ignore();
- cout << "9桁の数は? 123456789(Enter) ";
- cin.getline(na,sizeof(na));
- if( na[0] ){// 数字の入力があった場合
- for(int i=0;i<9;i++){
- g_nr[i]=int(na[i])-48; //int('0')=48 etc
- }
- }
- }
-
|