c++ B - Hanoi tower Gym - 101243B SDUT

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目大意:用一个汉诺塔,本题中的汉诺塔和一般汉诺塔有相同的规则,但是这道题求得是,当三个柱子上的盘子相等(也就是每个柱子上有N/3个盘子,这里的N mod 3 == 0)时的最小步骤

解题思路:
本题不能使用常规的递归,因为数据很大(递归一般在40以内可以递归,但这道题N 最大为300)。
本题其实是找规律的题:只是规律比较难找
N = 3 6 9 12 15 18
sum = 2 9 38 135 542 2079
sum = 2^1 +a[1]
2^3 +a[2]
2^5 +a[3]
2^7 +a[4]
2^9 +a[5]
2^11 +a[6]
现在主要是求出a数组,
a[1] = 0,a[2] = 1,a[3] = 6, a[4] = 7 ,a[5] = 30,a[6] = 31。
这样其实规律还是很难看出来,我就直接说了,当(n>1)时
a[n] = a[n-1] + 1 (n为偶数)
a[n] = a[n-1]*4+2 (n为奇数)
但是就算是知道了规律,这道题的难点其实是数据的储存,等N = 300时结果是:
"803469022129495137770981046171215126561215611592144769253375"大约有60位数,这远远超过longlong的范围。
这里有两个代码:一个是提前保存好结果直接输出,一个是正常计算

代码一:提前保存好结果
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
string ans[120] = { "2",
"9",
"38",
"135",
"542",
"2079",
"8318",
"32895",
"131582",
"524799",
"2099198",
"8390655",
"33562622",
"134225919",
"536903678",
"2147516415",
"8590065662",
"34359869439",
"137439477758",
"549756338175",
"2199025352702",
"8796095119359",
"35184380477438",
"140737496743935",
"562949986975742",
"2251799847239679",
"9007199388958718",
"36028797153181695",
"144115188612726782",
"576460752840294399",
"2305843011361177598",
"9223372039002259455",
"36893488156009037822",
"147573952598266347519",
"590295810393065390078",
"2361183241469182345215",
"9444732965876729380862",
"37778931863094600663039",
"151115727452378402652158",
"604462909807864343166975",
"2417851639231457372667902",
"9671406556919232420904959",
"38685626227676929683619838",
"154742504910681330455412735",
"618970019642725321821650942",
"2475880078570795734170337279",
"9903520314283182936681349118",
"39614081257132309534260330495",
"158456325028529238137041321982",
"633825300114115263698305023999",
"2535301200456461054793220095998",
"10141204801825837463773439328255",
"40564819207303349855093757313022",
"162259276829213372398777265029119",
"649037107316853489595109060116478",
"2596148429267413850294045183574015",
"10384593717069655401176180734296062",
"41538374868278621172359158709616639",
"166153499473114484689436634838466558",
"664613997892457937028364282443595775",
"2658455991569831748113457129774383102",
"10633823966279326985536299491456450559",
"42535295865117307942145197965825802238",
"170141183460469231740910675752738881535",
"680564733841876926963642703010955526142",
"2722258935367507707743890347601564794879",
"10889035741470030830975561390406259179518",
"43556142965880123323459523703856007479295",
"174224571863520493293838094815424029917182",
"696898287454081973173581491830620002713599",
"2787593149816327892694325967322480010854398",
"11150372599265311570770220319565615575597055",
"44601490397061246283080881278262462302388222",
"178405961588244985132295190914152631338270719",
"713623846352979940529180763656610525353082878",
"2854495385411919762116609717830853229927202815",
"11417981541647679048466438871323412919708811262",
"45671926166590716193865302138111296192894730239",
"182687704666362864775461208552445184771578920958",
"730750818665451459101843020821051317142553624575",
"2923003274661805836407372083284205268570214498302",
"11692013098647223345629481079581903386505809756159",
"46768052394588893382517924318327613546023239024638",
"187072209578355573530071668259090783432992763150335",
"748288838313422294120286673036363133731971052601342",
"2993155353253689176481146576088573851923483438612479",
"11972621413014756705924586304354295407693933754449918",
"47890485652059026823698344753189666898758131930628095",
"191561942608236107294793379012758667595032527722512382",
"766247770432944429179173514194124611452059698541363199",
"3064991081731777716716694056776498445808238794165452798",
"12259964326927110866866776219678353547520673527267065855",
"49039857307708443467467104878713414190082694109068263422",
"196159429230833773869868419485143095817481649838694072319",
"784637716923335095479473677940572383269926599354776289278",
"3138550867693340381917894711643447289308309891028789231615",
"12554203470773361527671578846573789157233239564115156926462",
"50216813883093446110686315385819787653847372230899364003839",
"200867255532373784442745261543279150615389488923597456015358",
"803469022129495137770981046171215126561215611592144769253375" };

int main()
{
    int n;
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
        while (cin >> n)
    {

        n /= 3;
        n--;
        cout << ans[n] << endl;
    }
}
代码二:将超大数分段储存
#include <bits/stdc++.h>

using namespace std;

/*全局变量*/
const long long N = 1000000000;
//取模的模数,将每个数分成数段,每段最多9位数,所以逢十位数向下一段进一
long long a[102][10];
long long b[102][10];//将a,b中的数分成每段最多9位数的数组
long long sum[9];

/*自定义函数*/
void compute_a();//计算a数组
void compute_b();//计算2的次方
void plus_a(int x,long long add);//a数组中两个数相加
void tiems_a(int x,int tiem);//a数组中两个数相乘
void tiems_b(int x, int tiem);//b数组中两个数相乘
void copy_a(int x);//将a[x-1]中的值赋给a[x]
void copy_b(int x);//将b[x-1]中的值赋给b[x]
void add_sum(int x);//a数组和b数组两数相加

int main()
{
    freopen("Input.txt", "r", stdin);
    freopen("Output.txt", "w", stdout);
    int n;
    long long cnt;
    compute_a();//计算a数组
    compute_b();//计算2的次方

    while (cin >> n)
    {
        int k = n / 3;
        memset(sum, 0, sizeof(sum));//每次都要初始化
        add_sum(k);//计算最终结果
        int flag = 0;
        //结果输出
        for (int i = 7; i > 0; i--)
        {
            if (sum[i] && !flag)
            {
                flag = 1;
                printf("%lld", sum[i]);
            }
            else if (sum[i])
            {
                printf("%09lld", sum[i]);
            }
        }
        printf("\n");
    }
    return 0;
}

/*自定义函数*/
void compute_b()//计算2的次方
{
    long long x = 1;
    memset(b, 0, sizeof(b));
    b[1][1] = 2;
    //这里求2的次方数是分成两段,不分也行
    for (int i = 2; i <= 25; i++)
    {
        b[i][1] = b[i - 1][1] * 4;
    }
    for (int i = 26; i <= 101; i++)
    {
        copy_b(i);
        tiems_b(i, 4);
    }
}

void compute_a()//计算a数组
{
    memset(a, 0, sizeof(a));
    //这里的a数组分成两段计算,其实不分也行
    for (int i = 2; i <= 30; i++)
    {
        if (i % 2)
        {
            a[i][1] = a[i - 1][1] * 4 + 2;
        }
        else
        {
            a[i][1] = a[i - 1][1] + 1;
        }
    }
    for (int i = 31; i <= 101; i++)
    {
        if (i % 2 == 0)
        {
            copy_a(i);//将a[x-1]中的值赋给a[x]
            plus_a(i,1);
        }
        else
        {
            copy_a(i);//将a[x-1]中的值赋给a[x]
            tiems_a(i,4);
            plus_a(i, 2);
        }
    }
}
void plus_a(int x,long long add)//a数组中的数相加上一个给定数
{
    int m = 0;
    a[x][1] = a[x][1] + add;
    for (int i = 1; i <= 6; i++)
    {
        m = a[x][i] / N;
        if (m)
        {
            a[x][i] = a[x][i] % N;
            a[x][i + 1] += m;
        }
        else
        {
            return;
        }
    }
}

void tiems_a(int x,int tiem)//a数组中数相乘以一个倍数
{
    long long m = 0;
    for (int i = 1; i <= 6; i++)
    {
        m = a[x][i - 1] / N;
        a[x][i] *= tiem;
        if (m)
        {
            a[x][i - 1] = a[x][i - 1] % N;
            a[x][i] += m;
        }
        if (!a[x][i]) return;
    }
}


void tiems_b(int x, int tiem)//b数组中数相乘以一个倍数
{
    long long m = 0;
    for (int i = 1; i <= 7; i++)
    {
        m = b[x][i - 1] / N;
        b[x][i] *= tiem;
        if (m)
        {
            b[x][i - 1] = b[x][i - 1] % N;
            b[x][i] += m;
        }
        if (!b[x][i]) return;
    }
}

void copy_a(int x)//将a[x-1]中的值赋给a[x]
{
    for (int i = 1; i <= 6; i++)
    {
        if (a[x - 1][i])
        {
            a[x][i] = a[x - 1][i];
        }
        else
        {
            return;
        }
    }
}

void copy_b(int x)//将b[x-1]中的值赋给b[x]
{
    for (int i = 1; i <= 7; i++)
    {
        if (b[x - 1][i])
        {
            b[x][i] = b[x - 1][i];
        }
        else
        {
            return;
        }
    }
}

void add_sum(int x)//a数组和b数组两数相加,计算出最终结果
{
    int m = 0;
    for (int i = 1; i <= 8; i++)
    {
        sum[i] = a[x][i] + b[x][i];
        sum[i] += m;
        m = sum[i] / N;
        sum[i] = sum[i] % N;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碧羽o(* ̄▽ ̄*)ブ回雪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值