跳转至

递归与递推

例题 #1 汉诺塔问题

1205

【题目描述】

约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到中间的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。

这是一个著名的问题,几乎所有的教材上都有这个问题。由于条件是一次只能移动一个盘,且不允许大盘放在小盘上面,所以64个盘的移动次数是:18,446,744,073,709,551,615

这是一个天文数字,若每一微秒可能计算(并不输出)一次移动,那么也需要几乎一百万年。我们仅能找出问题的解决方法并解决较小N值时的汉诺塔,但很难用计算机解决64层的汉诺塔。

假定圆盘从小到大编号为1, 2, ...

【输入】

输入为一个整数(小于20)后面跟三个单字符字符串。

整数为盘子的数目,后三个字符表示三个杆子的编号。

【输出】

输出每一步移动盘子的记录。一次移动一行。

每次移动的记录为例如 a->3->b 的形式,即把编号为3的盘子从a杆移至b杆。


下面是 P1096 [NOIP2007 普及组] Hanoi 双塔问题 的代码

#include <bits/stdc++.h>
using namespace std;
long long n, lc;
int a[222];

void chen() {
    for (int i = 0; i < lc; i++) //先加
        a[i] = a[i] * 2;

    for (int i = 0; i < lc; i++) { //进位
        a[i + 1] += a[i] / 10;
        a[i] %= 10;
    }
    if (a[lc] != 0)
        lc++;
}

void pre(int n) {
    a[0] = 1;
    lc = 1;
    //计算2^(n+1)-2
    for (int i = 1; i <= n + 1 ; i++) {
        chen();

    }
   a[0] -= 2;
    //借位
    for (int i = 0; i < lc; i++) {
        if (a[i] < 0) {
            a[i + 1] -= 1;
            a[i] += 10;
        } else
            break;
    }
}

int main() {
    //freopen("hanoi.in", "r", stdin);
    //freopen("hanoi.out", "w", stdout);

    cin >> n;
    pre(n);

    for (int i = lc-1; i>=0; i--) {
        cout << a[i];
    }
    return 0;
}

例题 #2 递推 矩形

题目描述

给出一个 \(n \times n\) 的矩阵,矩阵中,有些格子被染成白色,有些格子被染成黑色,现要求矩阵中白色**矩形**的数量。

输入格式

第一行,一个整数 \(n\),表示矩形的大小。

接下来 \(n\) 行,每行 \(n\) 个字符,这些字符为 \(\verb!W!\)\(\verb!B!\)。其中 \(\verb!W!\) 表示白格,\(\verb!B!\) 表示黑格。

输出格式

一个正整数,为白色矩形数量。

对于\(100\%\)的数据,\(n ≤ 150\)


典型O(n^3)扫描线,记录过去信息 匹配。

/*
Code bnxt Ntsc_Hodaka
*/

#include <bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define mp make_pair
#define pii pair<int,int>

///----///
#define rd read()
inline int read() {
    int xx = 0, ff = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            ff = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') xx = xx * 10 + (ch - '0'), ch = getchar();
    return xx * ff;
}
inline void write(int out) {
    if (out < 0)
        putchar('-'), out = -out;
    if (out > 9)
        write(out / 10);
    putchar(out % 10 + '0');
}

///----///
const int N = 2e2 + 5;
const int M = 1e7 + 5;
const int INF = 1e9 + 5;
const int MOD=1e9+7;
const double eps=1e-7;

bool f1;
///----///
int n,rt,idx,m;

int a[N][N], qz[N][N], fac[N],inv[N], g;
int ret, ans;
char s[N];
bool f2;


signed main(){
    n=rd;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            char c;
            cin>>c;
            if(c=='W')a[i][j]=0;
            else a[i][j]=1;
        }
    }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            qz[i][j]=qz[i-1][j]+a[i][j];
        }
    }

    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            int h=0;
            for(int k=1;k<=n;k++){
                if(qz[j][k]-qz[i-1][k])h=k;
                else ans+=k-h;
            }
        }
    }

    cout<<ans<<endl;
    return 0;
}


/*

*/