zoukankan      html  css  js  c++  java
  • 「基础算法」第1章 递推算法课堂过关

    「基础算法」第1章 递推算法课堂过关

    A. 【例题1】错排问题

    题意

    求多少个n个数的排列A,满足对于任意的(i (1leq i leq n) A_i eq i),输入n,输出一个整数,表示答案

    思路

    (f(n))表示n个数的合法方案排列个数

    1. 考虑第x个元素,把他放到k位置上,一共有 n-1种放法
    2. 考虑第k个元素,共两种可能:
      1. 把k放在位置n,则对于除k,n以外的其他元素,错排即可,共(f(n-2))种方案
      2. 不把k放在位置n,则对于n-1个元素的错排,有(f(n-1))种方法

    故,有递推式:

    [f(x)= left{ egin{aligned} (n-1)cdot (f(x - 1) + f(x - 2)) quad (xgeq3)\ 1qquadqquadqquadqquadqquadqquadqquad(x=1)\ 2qquadqquadqquadqquadqquadqquadqquad(x=2) end{aligned} ight. ]

    代码

    #include <iostream>
    #include <cstdio>
    #define int long long
    using namespace std;
    int n;
    int ans;
    int f(int x) {//数据异常水,记忆化都不用
    	if(x == 1) return 0;
    	if(x == 2) return 1;
    	return (x - 1) * (f(x - 1) + f(x - 2));
    }
    signed main() {
    	cin >> n;
    	cout << f(n);
    	cout << endl;
    	return 0;
    }
    /*
    0
    1
    3
    12
    56
    321
    2175
    17008
    150504
    1485465
    */
    

    B. 【例题2】奇怪汉诺塔

    题意

    有A、B、C、D四座塔, 给定n个圆盘,一开始全部放在A塔,直接输出n=1~12时的所有答案,无输入

    具体规则同普通汉诺塔

    思路

    回顾三座塔的情况:

    将A塔的n-1个圆盘移至B塔,最后一个圆盘直接移至C塔,再将B塔的所有圆盘移到C塔

    有递推式:

    [d(x)= left{ egin{aligned} &1+2cdot d(x - 1) qquad(xgeq2)\ &1qquadqquadqquadqquad(x=1) end{aligned} ight. ]

    当汉若塔数量为4座时:

    考虑将A塔的j个盘子转移到B塔(移动步数为(f(j))),然后不对B塔进行操作,将剩下n-j个盘子转移到D塔,移动步数为(d(n-j)),最后将B塔的j个盘子转移到D塔,移动步数为(f(j)),我们直接枚举j,取最小值即可

    递推式:

    [f(x)= left{ egin{aligned} &min {{d(x-j)+2cdot f(j)}} qquad(xgeq2,jin[0,x])\ &1qquadqquadqquadqquadqquadqquad (x=1) end{aligned} ight. ]

    代码

    #include <iostream>
    #include <cstdio>
    #define min_(_ , __) (_ < __ ? _ : __)
    using namespace std;
    int d[20] , f[20];
    int main() {
    	d[1] = 1;
    	for(int i = 1 ; i <= 12 ; i++)
    		d[i] = 2 * d[i - 1] + 1;
    	
    	f[1] = 1;
    	for(int i = 2 ; i <= 12 ; i++) {
    		
    		f[i] = (1 << 29);
    		for(int j = 0 ; j <= i ; j++)
    			f[i] = min_(f[i] , 2 * f[j] + d[i - j]);
    	}
    	
    	for(int i = 1 ; i <= 12 ; i++)
    		cout << f[i] << endl;
    	return 0;
    }
    /*答案
    1
    3
    5
    9
    13
    17
    25
    33
    41
    49
    65
    81
    */
    

    C. 【例题3】数的划分

    题意

    将整数n分成k份,每份不为空,求不同的划分方案数(数字相同而顺序不同的两个方案视为相同的方案)

    例如:下面三种分法被认为是相同的:

    1,1,5; 1,5,1; 1,1,5.
    

    思路

    设$ f(n,k)$表示将整数n分成k份的不重复方案数

    (n>k)时:

    1. k份中至少有一份为“1”:方案数为(f(n-1,k-1))
    2. k份中没有一份为“1” :方案数为(f(n-k,k))(在n-k被分成k份的基础上,每一份都加上“1”)

    故有递推式:

    [f(n,k)= left{ egin{aligned} &f(n-1,k-1)+f(i-k,k) qquad (x>k)\ &1qquadqquadqquadqquadqquadqquadqquad(n=k)\ &0qquadqquadqquadqquadqquadqquadqquad(n<k) end{aligned} ight. ]

    代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int n , k;
    int f[1010][1010];
    int main() {
    	cin >> n >> k;
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = 1 ; j <= k ; j++) {
    			if(i == j)	f[i][j] = 1;
    			else if(i < j)	f[i][j] = 0;
    			else f[i][j] = f[i - 1][j - 1] + f[i - j][j];'
    		}
    	cout << f[n][k];
    	return 0;
    }
    

    D. 【例题4】传球游戏

    题目

    传送门

    思路

    (f(i , j)) 表示经过j次传球后,球落在第i个同学手中的方案数(说明一下,我代码里面把游戏刚开始,球在小蛮手上的情况当做第1次传球,故有一丢丢不一样)

    很显然,有:

    [f(i,j)=f(i-1,j-1)+f(i+1,j-1) ]

    其中,根据题目“n 个同学站成一个圆圈”的背景,“i+1” 、"i-1"均应该在([1,n])范围内,越界自行处理

    代码

    #include <iostream>
    #include <cstdio>
    #define ll long long
    using namespace std;
    int n , m;
    ll f[3010][3];
    int main() {
    	cin >> n >> m;
    	++m;
    	f[1][1] = 1;
    	for(int i = 2 ; i < m ; i++) {
    		for(int j = 1 ; j <= n ; j++){
    			f[j][i & 1] = 0;
    				f[j][i & 1] = f[j == 1 ? n : j - 1][(i - 1) & 1] + f[j == n ? 1 : j + 1][(i - 1) & 1];
    		}
    	}
    	cout << f[n][(m - 1) & 1] + f[2][(m - 1) & 1] << endl;
    	
    	return 0;
    }
    

    E. 【例题5】平铺方案

    题目

    思路

    想出并写出算法10min,写出高精度40min

    (f(x))表示铺成2*x的矩形的方案数

    显然(f(1)=1,f(2)=3)

    对于其他情况,我们考虑:

    1. 将1*2的矩形竖着拼到2*(n-1)的矩形上,方案数为f(x-1)
    2. 将两个1*2的矩形横着拼到2*(n-2)的矩形上,方案数为f(x-2)
    3. 将一个2*2的矩形横着拼到2*(n-2)的矩形上,方案数为f(x-2)

    故递推式:

    [f(x)= left{ egin{aligned} &2cdot f(x - 2) + f(x - 1) quad(xgeq3)\ &1qquadqquadqquadqquadqquad(x=1)\ &3qquadqquadqquadqquadqquad(x=2) end{aligned} ight. ]

    最后,看样例都知道要高精度

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    	#define m 1010
    struct bignum {
    	int a[m];
    	int siz;
    	
    	void init() {
    		memset(a , 0 , sizeof(a));
    		this->siz = 0;
    	}
    	void print() {
    //		cout << siz << endl;
    		for(int i = 0 ; i < siz ; i++)
    			putchar(a[siz - i - 1] + '0');
    		putchar('
    ');
    	}
    	bignum operator + (const bignum &b) const{
    		bignum ans;
    		ans.init();
    		
    		int g = 0;
    		ans.siz = (siz > b.siz ? siz : b.siz) - 1;
    		for(int i = 0 ; i <= ans.siz || g != 0 ; i++) {
    			if(i > ans.siz)
    				ans.siz = i;
    			ans.a[i] = g + a[i] + b.a[i];
    			g = ans.a[i] / 10;
    			ans.a[i] %= 10;
    		}
    		++ans.siz;
    		if(ans.a[ans.siz - 1] == 0)--ans.siz;
    		return ans;
    	}
    };
    
    bignum f[1010];
    int main() {
    	
    	int n;
    	int maxn = 3;
    	
    	f[1].siz = 1 , f[1].a[0] = 1;
    	f[2].siz = 1 , f[2].a[0] = 3;
    	
    	
    	while(cin >> n) {
    		for(; maxn <= n ; maxn++)
    			f[maxn] = f[maxn - 1] + f[maxn - 2] + f[maxn - 2];
    		
    		f[n].print();
    		if(n > maxn) maxn = n;
    	}
    	return 0;
    } 
    
  • 相关阅读:
    Activity-fragment-ListView展示
    Android-fragment简介-fragment的简单使用
    Android-LoaderManager异步加载数据库数据
    Android-上下文菜单Menu
    Android-普通菜单Menu
    Android-Git命令行操作
    zabbix安装步骤
    redis安装及简单使用
    ansible安装
    ansible-palybook
  • 原文地址:https://www.cnblogs.com/dream1024/p/14159789.html
Copyright © 2011-2022 走看看