2018年3月31日 星期六

Re: n 取 n 逆時鐘旋轉排列法(水果盤排列程式)

// test004.cpp: 定義主控台應用程式的進入點。
//(水果盤排列程式)
//恭喜你設計出新的排列組合程式,
//我幫你做了一個有define變數的水果盤排列程式,
//n--->A , r--->B ,
//並且計算出Cnr的組合數字,取名為N3。
//設定組合總數為N2,排列所有組合的數量為N3,
//預估N = N3 + 1。
//詹宗運製作,版本: Visual C++ 2017 20180403新版
//

#include "stdafx.h"
#include <functional>  // std::function
#include <memory>    // std::shared_ptr
#include <vector>
#include <iostream>
#include <exception>    // exception
#include <stdexcept>    // exception
#include <new>          // exception
#include <typeinfo>     // exception
//#include <windows.h>//myerrorhandler
//#include <stdarg.h>//myerrorhandler
#include <stdio.h>//cout
//#include <rtcapi.h>//myerrorhandler

//#include <ostream>//fopen

#include <stdlib.h>//calloc
#include <iostream>//cout
using namespace std;
#include <iomanip>//setw()
//
//
//#include <fstream>//fopen
//#include <memory.h>//typeinfo
//#include <typeinfo>//typeinfo
//#include <string.h>//string
//#include <cstring>//string
//#include <cstddef>//string

//using namespace std;

#define A 10
#define B 5
#define SLOT_SIZE 10

//從1開始遞增
int N = 1;
//新增例外類別

const exception* Logic_Error = new exception("Logic_Error");

//if ((int)A > (int)SLOT_SIZE) throw Logic_Error;
//if ((int)B > (int)SLOT_SIZE) throw Logic_Error;


const char* Make_Slot(int);
//---
//儲存節目名稱的結構
struct show_slot
{
int id;
const char* name;
};


show_slot s_slot[SLOT_SIZE - 1];

void load_slot() {
for (int i = 0; i < (SLOT_SIZE - 1); i++)
{
s_slot[i].id = i;
}
//這裡是儲存水果名稱的結構
//可以透過修改字串來改變水果的名稱
s_slot[0].name = "蘋果";
s_slot[1].name = "香蕉";
s_slot[2].name = "番茄";
s_slot[3].name = "橘子";
s_slot[4].name = "柳丁";
s_slot[5].name = "西瓜";
s_slot[6].name = "芭樂";
s_slot[7].name = "哈密瓜";
s_slot[8].name = "火龍果";
s_slot[9].name = "葡萄";
}

// n 取 r 做排列
// 採用逆時旋轉排列法
// 必須 n >= r
class Permutation_nPn
{
// 回報結果
function<void(const shared_ptr<vector<unsigned char> > &, size_t)> m_Report;
// 放置要排列的數字
shared_ptr <vector<unsigned char> > m_Digital_Array;
// 要做排列的數目值
size_t m_r;

void v(size_t n, size_t r)
{
size_t i = n + 1;
while (i--)
{
if (r == 0)
m_Report(m_Digital_Array, m_r);
else
v(n - 1, r - 1);
unsigned char tmp = m_Digital_Array->at(n);
for (size_t j = n; j > 0; --j)
m_Digital_Array->at(j) = m_Digital_Array->at(j - 1);
m_Digital_Array->at(0) = tmp;
}
}

public:
// Permutation_nPn() {}

Permutation_nPn(const function<void(const shared_ptr<vector<unsigned char> > &, size_t)> &Receive)
:m_Report(Receive)
{}

void nPr(size_t n, size_t r)
{
m_r = r;
m_Digital_Array = shared_ptr<vector<unsigned char> >(new vector<unsigned char>(n));
size_t i = n;
while (i--)
{
m_Digital_Array->at(i) = i;
}
v(n - 1, r - 1);
}
};

void startmsg()
{
cout << "簡易水果排列程式!" << endl;
cout << "從" << A << "種水果任取" << B << "種水果的排列如下所示:" << endl;

}

void Show(const shared_ptr<vector<unsigned char> > &Digital_Array, size_t r)
{
cout << "第\t" << N << "組:\t\t";
for (size_t i = Digital_Array->size() - 1; r > 0; --i, --r)
cout << Make_Slot((int)Digital_Array->at(i)) << ' '; //利用此行輸出水果的種類
cout << endl;
++N;
}

const char* Make_Slot(int s)
{

if (s > SLOT_SIZE) throw Logic_Error;

int tmp003 = s;
if (tmp003 < 0) throw Logic_Error;

return s_slot[tmp003].name;

}

int cnt(int tmp001)
{
int i;
int num001 = 1;
for (i = 0; i < tmp001; i++)
num001 = num001 * (i + 1);
return num001;
}

int cntN(int tmpA, int tmpB)
{
int tmp002;
if (tmpA < tmpB)throw Logic_Error;
try {
int tmpC = cnt(tmpA);
int tmpD = cnt(tmpB);
int tmpE = cnt(tmpA - tmpB);
tmp002 = tmpC / (tmpD*tmpE);

//tmp002 = cnt(tmpA) / cnt(tmpB)*cnt(tmpA - tmpB);
}
catch (const exception& e) {
cout << e.what() << endl;
system("PAUSE");
exit(-1);
}
if (tmp002 > 0) {
return tmp002;
}
else { throw Logic_Error; }
}

int main()
{
//function<void(const shared_ptr<vector<unsigned char> > &, size_t)> Reprot(Show);
Permutation_nPn P(Show);

startmsg(); //秀出起始訊息
load_slot();   //載入水果結構名稱

   //進行計算
   //N從1開始遞增
N = 1;
int N2 = cntN(A, B);
int N3 = cnt(B)*N2;
//if (N2 != N) {
cout << "A=" << A << endl;
cout << "B=" << B << endl;
cout << "N2=" << N2 << endl;
cout << "N3=" << N3 << endl;

if (N3 > 40000) {
cout << "N3組合數字過大,取消顯示,程式結束。" << endl;
system("PAUSE");
exit(-1);
}
cout << "將開始計算,請準備。" << endl;

system("PAUSE");

//主程式
P.nPr(A, B);
//驗算
N2 = cntN(A, B);

cout << "A=" << A << endl;
cout << "B=" << B << endl;
cout << "N=" << N << "( = N3 + 1 )" << endl;  // N = N3+1 ,否則就是算錯了
cout << "N2=" << N2 << endl;
cout << "N3=" << N3 << endl;

cout << "計算完成。" << endl;


system("PAUSE");

return 0;
}

1 則留言:

  1. 2018/4/3 網址已經更新,修正了cxxlman大大指出的錯誤。加上了我的簽名。這個程式可以利用排列組合來計算水果盤種類,是一個很有趣的程式!程式要修改的話只要調整A和B的數字,以及s_slot的名稱就可以了,Cnr當中的n--->A, r--->B。

    回覆刪除