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

梦想的初衷 提交于 2020-01-03 05:44:08

问题


So I'm working on a homework assignment and I need to create recursive functions for partitions, Stirling numbers(first and second kind), and Chebyshev polynomials of the first. My program should be able to have a user input a positive integer n, and then create files named Partitions.txt, Stirling1.txt, Stirling2.txt, and Chebyshev.txt, that creates a table of all values f(k,m) for 1<=k<=n and 1<=m<=n. I'm struggling just to start off the assignment and feel like I have no understanding of it even though I've been doing research and trying to figure it out. If someone can help me out, I'd really appreciate it! Thank you!

    #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);
    }

And here's my Output .h file

    #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

回答1:


This is really several questions in one, so I will take it in parts.

Partitioning

This is probably the hardest of these tasks, but it's pretty doable if you break it down.

What are all the partitions of a number n? The first number in each partition must be between 1 and n. Since we don't care about order, let's just always keep the numbers in descending order. So the first list of partitions looks something like this:

  • {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}

But wait! We can say that more simply. That's just

  • [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]

Which is really just all the partitions starting with n - i for all i between 1 and n. So, if we can find a way to get each group of partitions for each i, we can simplify things.

How might we do that? Well, if we think about it, we can realize that we can get every partition which starts with n - i pretty easily. Each partition is just n - i followed by a way to get numbers which add up to i... which is exactly what a partition is, so we've found our recursive case! We get all of our partitions by getting n - i followed by each of the partitions of i.

Now we just need a base case. That's pretty simple: we can just define the partitions for zero to be the empty set.

Putting It All Together

So what does this look like?

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;
}

Stirling Numbers

These are pretty similar. If you look at their respective Wikipedia pages, you can find recurrence relations for each kind:

First Kind

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

Second Kind

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

And they have the same base cases: S(0, 0) = 1, S(n, 0) = 0 and S(0, n) = 0.

So you could define a function to calculate them something like this:

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);
}

and the one for the second kind would look very similar to that.

Chebyshev Polynomials

It's not totally clear what the requirement is here. I'm going to assume it's to evaluate one at a point, not to come up with some expanded representation. It goes pretty much the same as the Stirling Numbers.

Again, the wikipedia page has a recurrence relation:

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

I assume you can figure out how to make that into a function. (Hint: basically all it takes is turning those left-hand sides into if statements, similar to the example above.)



来源:https://stackoverflow.com/questions/25049552/recursive-functions-for-partitions-stirling-numbers-and-chebyshev-polynomials

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!