离散数学——冯诺依曼邻居问题

离散数学——冯诺依曼邻居问题

/ 1评 / 3688次 / 5

Problem:

Analysis:

递推问题从状态入手

容易发现在每一轮扩增时,扩增的来源细胞一定是上一轮的新增细胞。即有第\(n\)轮扩增时的来源细胞有\(T(n)-T(n-1)\)

接下来容易发现除上下两细胞外,所有的细胞可分为左右两部分,分别向左右扩增一个单位。上下两细胞又另外分别向四周扩增\(3\)个单位

于是有递推方程为\(T(n+1)-T(n)=T(n)-T(n-1)-2+6\)

显然可以得到一个二阶等差数列。

可以通过解非齐次线性方程或是待定系数法解之,这里因为形式特殊(二阶等差数列)故使用待定系数法

于是设\(T(n)=an^2+bn+c\)

将初始\(T(0)=1\),\(T(1)=5\),\(T(2)=13\)代入即可解得

\(T(n)=2n^2+2n+1\)

关于代码,则同样有两种解法,一种是\(O(1)\)的直接计算,另一种是\(O(n)\)的动态规划预处理,这里我们都提供。

其中两种方法均支持一万位以内的答案计算,但是递推法相对慢得多,不具有普适性

/*
 * @Author       : Gehrychiang
 * @LastEditTime : 2020-06-27 14:13:39
 * @Website      : www.yilantingfeng.site
 * @E-mail       : gehrychiang@aliyun.com
 * @ProbTitle    : 离散数学——冯诺依曼邻居问题
 */
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 10000, BASE = 1000000000, WIDTH = 9; //压位
char in[10005];
struct bigint
{
    ll element[maxn]; //用来存放每一位(元)
    ll len;
    bigint operator=(ll num) //从ll向bigint转换
    {
        memset(element, 0, sizeof(element));
        len = 0;
        while (num > 0)
        {
            element[len++] = num % BASE;
            num /= BASE;
        }
        return *this;
    }
    bigint operator=(const char *str) //从str向bigint转换
    {
        memset(element, 0, sizeof(element));
        ll num_len = strlen(str);
        len = (num_len + WIDTH - 1) / WIDTH;
        int pos = 0;
        for (int i = num_len - 1; pos < len; i -= WIDTH)
        {
            for (int j = 0; j < WIDTH; j++)
            {
                element[pos] += (str[i - j] - '0') * pow(10, j);
                if (i - j == 0)
                {
                    break;
                }
            }
            pos++;
        }
        return *this;
    }
    bool operator<(const bigint &b) const //bigint小于比较
    {
        if (b.len != len)
        {
            return len < b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] < b.element[i];
            }
        }
        return false;
    }
    bool operator<=(const bigint &b) const //bigint小于等于比较
    {
        if (b.len != len)
        {
            return len < b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] < b.element[i];
            }
        }
        return true;
    }
    bool operator>(const bigint &b) const //bigint大于比较
    {
        if (b.len != len)
        {
            return len > b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] > b.element[i];
            }
        }
        return false;
    }
    bool operator>=(const bigint &b) const //bigint大于等于比较
    {
        if (b.len != len)
        {
            return len > b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] > b.element[i];
            }
        }
        return true;
    }
    bool operator==(const bigint &b) const //bigint等于比较
    {
        if (b.len != len)
        {
            return false;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return false;
            }
        }
        return true;
    }
    bigint operator+(const bigint &b) const //bigint加法
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = len;
        for (int i = 0; i < len; i++)
        {
            ans.element[i] += element[i] + b.element[i]; //加
            if (ans.element[i] >= BASE)                  //如果多了就借位
            {
                ans.element[i + 1] += ans.element[i] / BASE;
                ans.element[i] %= BASE;
            }
        }
        ans.len++;
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    bigint operator-(const bigint &b) const //bigint减法
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = len;
        for (int i = 0; i < len; i++)
        {
            ans.element[i] += element[i] - b.element[i]; //减
            if (ans.element[i] < 0)                      //如果多了就借位
            {
                ans.element[i] += BASE;
                ans.element[i + 1]--;
            }
        }
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    bigint operator*(const bigint &b) const //bigint乘法
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = 2 * len;
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < b.len; j++)
            {
                ans.element[i + j] += element[i] * b.element[j]; //乘
                if (ans.element[i + j] >= BASE)                  //如果多了就借位
                {
                    ans.element[i + j + 1] += ans.element[i + j] / BASE;
                    int cur = i + j + 1;
                    while (ans.element[cur] >= BASE)
                    {
                        ans.element[cur + 1] += ans.element[cur] / BASE;
                        ans.element[cur] %= BASE;
                        cur++;
                    }
                    ans.element[i + j] %= BASE;
                }
            }
        }
        ans.len++;
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    bigint operator/(const ll &b) const //bigint除法 element len/b(先撸个半成品,这玩意儿太鬼畜了)
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = len;
        ans.element[len - 1] = (element[len - 1]) / b;
        ll lef = element[len - 1] % b;
        for (int i = len - 2; i >= 0; i--)
        {
            ans.element[i] = (element[i] + lef * BASE) / b;
            lef = (element[i] + lef * BASE) % b;
        }
        ans.len++;
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    void bigint_init()
    {
        memset(element, 0, sizeof(element));
        len = 0;
    }
    bool bigint_read()
    {
        memset(in, 0, sizeof(in));
        scanf("%s", in);
        // if (!(strlen(in) == 1 && in[0] == '0'))
        //     return false;
        *this = in;
        return true;
    }
    void bigint_print()
    {
        if (len == 0)
            printf("0");
        else
        {
            printf("%lld", element[len - 1]);
            for (int i = len - 2; i >= 0; i--)
            {
                printf("%09lld", element[i]);
            }
        } //注意输出的时候除了第一位其他不够位数都用0补齐(避免遗漏前缀0)
        printf("\n");
    }
};
int main()
{
    cout << "Please enter the target number: ";
    bigint maxm;
    maxm.bigint_init();
    maxm.bigint_read();

    bigint ans;
    ans.bigint_init();
    ans = maxm;

    bigint a;
    a.bigint_init();

    bigint b;
    b.bigint_init();

    bigint one;
    one.bigint_init();
    one = 1;

    bigint two;
    two.bigint_init();
    two = 2;

    a = ans * ans;
    a = a * two;
    b = ans * two;
    ans = a;
    ans = ans + b;
    if (ans < one)
    {
        ans = one + ans;
    }
    else
    {
        ans = ans + one;
    }
    cout << "The answer is: ";
    ans.bigint_print();
}
/*
 * @Author       : Gehrychiang
 * @LastEditTime : 2020-06-27 13:57:53
 * @Website      : www.yilantingfeng.site
 * @E-mail       : gehrychiang@aliyun.com
 * @ProbTitle    : 离散数学——冯诺依曼邻居问题(dp算法)(slow)
 */
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 10000, BASE = 1000000000, WIDTH = 9; //压位
char in[10005];
struct bigint
{
    ll element[maxn]; //用来存放每一位(元)
    ll len;
    bigint operator=(ll num) //从ll向bigint转换
    {
        memset(element, 0, sizeof(element));
        len = 0;
        while (num > 0)
        {
            element[len++] = num % BASE;
            num /= BASE;
        }
        return *this;
    }
    bigint operator=(const char *str) //从str向bigint转换
    {
        memset(element, 0, sizeof(element));
        ll num_len = strlen(str);
        len = (num_len + WIDTH - 1) / WIDTH;
        int pos = 0;
        for (int i = num_len - 1; pos < len; i -= WIDTH)
        {
            for (int j = 0; j < WIDTH; j++)
            {
                element[pos] += (str[i - j] - '0') * pow(10, j);
                if (i - j == 0)
                {
                    break;
                }
            }
            pos++;
        }
        return *this;
    }
    bool operator<(const bigint &b) const //bigint小于比较
    {
        if (b.len != len)
        {
            return len < b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] < b.element[i];
            }
        }
        return false;
    }
    bool operator<=(const bigint &b) const //bigint小于等于比较
    {
        if (b.len != len)
        {
            return len < b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] < b.element[i];
            }
        }
        return true;
    }
    bool operator>(const bigint &b) const //bigint大于比较
    {
        if (b.len != len)
        {
            return len > b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] > b.element[i];
            }
        }
        return false;
    }
    bool operator>=(const bigint &b) const //bigint大于等于比较
    {
        if (b.len != len)
        {
            return len > b.len;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return element[i] > b.element[i];
            }
        }
        return true;
    }
    bool operator==(const bigint &b) const //bigint等于比较
    {
        if (b.len != len)
        {
            return false;
        }
        for (int i = b.len - 1; i >= 0; i--)
        {
            if (b.element[i] != element[i])
            {
                return false;
            }
        }
        return true;
    }
    bigint operator+(const bigint &b) const //bigint加法
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = len;
        for (int i = 0; i < len; i++)
        {
            ans.element[i] += element[i] + b.element[i]; //加
            if (ans.element[i] >= BASE)                  //如果多了就借位
            {
                ans.element[i + 1] += ans.element[i] / BASE;
                ans.element[i] %= BASE;
            }
        }
        ans.len++;
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    bigint operator-(const bigint &b) const //bigint减法
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = len;
        for (int i = 0; i < len; i++)
        {
            ans.element[i] += element[i] - b.element[i]; //减
            if (ans.element[i] < 0)                      //如果多了就借位
            {
                ans.element[i] += BASE;
                ans.element[i + 1]--;
            }
        }
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    bigint operator*(const bigint &b) const //bigint乘法
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = 2 * len;
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < b.len; j++)
            {
                ans.element[i + j] += element[i] * b.element[j]; //乘
                if (ans.element[i + j] >= BASE)                  //如果多了就借位
                {
                    ans.element[i + j + 1] += ans.element[i + j] / BASE;
                    int cur = i + j + 1;
                    while (ans.element[cur] >= BASE)
                    {
                        ans.element[cur + 1] += ans.element[cur] / BASE;
                        ans.element[cur] %= BASE;
                        cur++;
                    }
                    ans.element[i + j] %= BASE;
                }
            }
        }
        ans.len++;
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    bigint operator/(const ll &b) const //bigint除法 element len/b(先撸个半成品,这玩意儿太鬼畜了)
    {
        bigint ans;
        memset(ans.element, 0, sizeof(ans.element));
        ans.len = len;
        ans.element[len - 1] = (element[len - 1]) / b;
        ll lef = element[len - 1] % b;
        for (int i = len - 2; i >= 0; i--)
        {
            ans.element[i] = (element[i] + lef * BASE) / b;
            lef = (element[i] + lef * BASE) % b;
        }
        ans.len++;
        while (ans.element[ans.len - 1] == 0 && ans.len > 0) //清除空白高位
        {
            ans.len--;
        }
        return ans;
    }
    void bigint_init()
    {
        memset(element, 0, sizeof(element));
        len = 0;
    }
    bool bigint_read()
    {
        memset(in, 0, sizeof(in));
        scanf("%s", in);
        // if (!(strlen(in) == 1 && in[0] == '0'))
        //     return false;
        *this = in;
        return true;
    }
    void bigint_print()
    {
        if (len == 0)
            printf("0");
        else
        {
            printf("%lld", element[len - 1]);
            for (int i = len - 2; i >= 0; i--)
            {
                printf("%09lld", element[i]);
            }
        } //注意输出的时候除了第一位其他不够位数都用0补齐(避免遗漏前缀0)
        printf("\n");
    }
};
int main()
{
    cout << "Please enter the target number: ";
    ll maxm;
    cin >> maxm;
    bigint a;
    a.bigint_init();
    a = 1;
    bigint b;
    b.bigint_init();
    b = 5;
    bigint c;
    c.bigint_init();

    bigint q;
    q.bigint_init();
    q = 2;
    bigint w;
    w.bigint_init();
    w = 4;
    for (ll i = 2; i <= maxm; i++)
    {
        if (i % 3 == 2)
        {
            c = b * q;
            c = c - a;
            c = c + w;
        }
        else if (i % 3 == 0)
        {
            a = c * q;
            a = a - b;
            a = a + w;
        }
        else
        {
            b = a * q;
            b = b - c;
            b = b + w;
        }
    }
    cout << "The answer is: ";
    if (maxm % 3 == 0)
    {
        a.bigint_print();
    }
    else if (maxm % 3 == 1)
    {
        b.bigint_print();
    }
    else
    {
        c.bigint_print();
    }
}

《“离散数学——冯诺依曼邻居问题”》 有 1 条评论

  1. 匿名说道:

    噜噜噜噜噜噜噜

发表回复

您的电子邮箱地址不会被公开。

你好 No.62465