递归函数的分区,斯特林数,和切比雪夫多项式的第一

Recursive functions for partitions, stirling numbers, and chebyshev polynomials of the first

本文关键字:多项式 分区 斯特林 递归函数      更新时间:2023-10-16

所以我正在做一个家庭作业,我需要为分区,斯特林数(第一和第二类)和第一种的切比雪夫多项式创建递归函数。我的程序应该能够让用户输入一个正整数n,然后创建名为Partitions.txt、Stirling1.txt、Stirling2.txt和Chebyshev.txt的文件,这将创建一个表,其中包含1<=k<=n和1<=m<=n的所有值f(k,m)。我刚开始做作业就很挣扎,感觉自己一点也不懂,尽管我一直在做研究,试图弄清楚它。如果有人能帮我,我会很感激的!谢谢你!

    #include <iostream>
    #include <vector>
    #include "OutputFile.h"
    using namespace std;
    using namespace OutputStream;

    int firstKindStirling();
    vector<vector<int> > getPartitions(int number, int maxElement);
    int main() {
        cout << "Welcome! Please input a number m:";
        int m;
        cin>>m;

        OFile fout("Partitions.txt");
        return 0;
    }
    vector<vector<int> > getPartitions(int number, int maxElement)
    {
        if (number < 1) 
            return vector<vector<int>>();
       vector<vector<int>> partitions;
        if (number <= maxElement) 
            partitions.push_back(number); //for some reason this doesn't want to work. Not sure what I'm missing here. 
        for (int i = number - maxElement; i < number; ++i)
        {
            // (recursively) get the partitions of `i`, with elements no larger than `n - i`
            auto partitionsForI = getPartitions(i, number - i);
            // add `n - i` to the front of all of those partitions
            for(vector<int>& partition : partitionsForI)
            {
                partition.insert(partition.begin(), number - i);
            }
            // add these new partitions to our list.
            partitions.insert(partitions.end(), partitionsForI.begin(), partitionsForI.end());
        }
        return partitions;
    }
    int firstKindStirling(int n, int k) 
    {
        if (n == 0 && k == 0) return 1;
        else if (n == 0 || k == 0) return 0;
        else return -(n-1) * firstKindStirling(n-1, k) + firstKindStirling(n-1, k-1);
    }

这是我的Output .h文件

    #ifndef OUTPUT_H
    #define OUTPUT_H
    #include <fstream>
    #include <string>
    #include <vector>
    #include <iostream>
    #include <sys/stat.h>
    #include <sstream>
    #include <memory>
    namespace OutputStream {
        class OFile {
            std::ofstream file;
        public:
            OFile(std::string filename, size_t output_precision = 10) {
                file.open(filename);
                if(file.fail()) throw std::runtime_error("Error: cannot open file");
                file.precision(output_precision);
            };
            /*
            OFile& operator<<(int x) {
                file<<x;
                return *this;
            }
            */
            /*
            OFile& operator<<(const Point2D& p) {
                file<<p;
                return *this;
            }
            */
            OFile& operator<<(const std::vector<int>& v) {
                for(auto x : v) file<<x<<std::endl;
                return *this;
            }

            template<typename T>
            OFile& operator<<(const T& p) {
                file << p;
                return *this;
            }

            ~OFile() { file.close(); };
        };

        // Strongly enumerate type
        enum class FileType { Input, Output, SafeOutput };
        // Partial Template Specialization
        template<FileType> class File;
        template<>
        class File < FileType::Input > {
        public:
            File( const std::string& filename ) : fin(filename) {
                if(fin.fail()) throw std::runtime_error("Error opening file: "+filename);
            };
            /** ...
            IFile& allows for syntax like
            fin>>a>>b>>c;
            */
            File& operator>>(int& a) {
                fin>>a;
                return *this;
            }
            /**...*/
            operator bool() {
                return !(fin.fail());
            }
            operator std::string() {
                return "Active";
            }
            // operator [data type]() {
                // code here
            //  return [object of type data type];
            // }
            friend File& getline( File& fin, std::string& line) {
                getline( fin.fin, line);
                return fin;
            }
            friend File& getrow( File& fin, std::vector<int>& rows);
            friend File& getmatrix( File& fin, std::vector< std::vector<int> >& table);
            ~File() { fin.close(); };
        private:
            std::ifstream fin;
        };  
        template<>
        class File < FileType::Output > {
            std::ofstream file;        
        public:
            File(std::string filename, size_t output_precision = 10) {
                file.open(filename);
                if(file.fail()) throw std::runtime_error("Error: cannot open file");
                file.precision(output_precision);
            };
            /*
            OFile& operator<<(int x) {
                file<<x;
                return *this;
            }
            */
            /*
            OFile& operator<<(const Point2D& p) {
                file<<p;
                return *this;
            }
            */
            File& operator<<(const std::vector<int>& v) {
                for(auto x : v) file<<x<<std::endl;
                return *this;
            }

            template<typename T>
            File& operator<<(const T& p) {
                file << p;
                return *this;
            }

            ~File() { file.close(); };
        };
    }
    #endif

这真是几个问题合二而三,所以我将分几个部分来回答。

<标题>分区h1> 可能是这些任务中最难的,但如果你分解它,它是非常可行的。

一个数字n的所有分区是什么?每个分区的第一个数字必须在1到n之间,因为我们不关心顺序,所以我们总是把数字按降序排列。因此,第一个分区列表看起来像这样:

  • {n}
  • {n-1, 1}
  • {n-2, 2}, {n - 2, 1, 1}
  • {n-3, 3}, {n - 3, 2, 1}, {n - 3, 1, 1, 1}
  • {1, 1, ..., 1}

但等等!我们可以更简单地说。这是

  • [the set of partitions starting with n]
  • [the set of partitions starting with n - 1]
  • [the set of partitions starting with n - 2]
  • [the set of partitions starting with 1]

它实际上是1到n之间所有i的所有以n - i开头的分区。因此,如果我们能找到一种方法来获得每个i的每一组分区,我们就可以简化事情。

我们该怎么做呢?如果我们考虑一下,我们可以意识到我们可以很容易地得到每个以n - i开头的分区。每个分区只是n - i,然后是一种方法来获得加起来是i的数字…这就是分区,我们找到了递归的情况!我们通过获取n - ii的每个分区来获得所有的分区。

现在我们只需要一个基本情况。这很简单:我们可以定义0为空集的分区。

把它放在一起

这看起来像什么?

vector<vector<int>> getPartitions(int number, int maxElement)
{
    if (number < 1) return vector<vector<int>>();
    vector<vector<int>> partitions;
    if (number <= maxElement) partitions.push_back({number});
    for (int i = number - maxElement; i < number; ++i)
    {
        // (recursively) get the partitions of `i`, with elements no larger than `n - i`
        auto partitionsForI = getPartitions(i, number - i);
        // add `n - i` to the front of all of those partitions
        for(vector<int>& partition : partitionsForI)
        {
            partition.insert(partition.begin(), number - i);
        }
        // add these new partitions to our list.
        partitions.insert(partitions.end(), partitionsForI.begin(), partitionsForI.end());
    }
    return partitions;
}
<标题>斯特林数字

它们非常相似。如果你查看它们各自的维基百科页面,你可以找到每一种类型的递归关系:

第一种

s1(n, k) = -(n - 1) * s1(n - 1, k) + s1(n - 1, k - 1)

二类

S2(n, k) = k * S2(n - 1, k) + S2(n - 1, k - 1)

它们有相同的基本情况:S(0, 0) = 1, S(n, 0) = 0S(0, n) = 0

你可以定义一个函数来计算它们像这样:

int firstKindStirling(int n, int k) 
{
    if (n == 0 && k == 0) return 1;
    else if (n == 0 || k == 0) return 0;
    else return -(n-1) * firstKindStirling(n-1, k) + firstKindStirling(n-1, k-1);
}

和第二种格式的格式看起来非常相似。

<标题> 切比雪夫多项式

这里的要求并不完全清楚。我假设它是在一点上求1的值,而不是给出一些扩展的表示。这和斯特林数差不多。

同样,维基百科页面有一个递归关系:

chebyshev(0, x) = 1
chebyshev(1, x) = x
chebyshev(n, x) = 2 * x * chebyshev(n-1, x)  -  chebyshev(n-2, x)

我想你可以弄清楚如何把它变成一个函数。(提示:基本上所需要做的就是把左边的语句变成if语句,类似于上面的例子。)