ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一周总结11.15~11.21——dfs、杨辉三角形、dp

2021-11-21 16:59:12  阅读:250  来源: 互联网

标签:输出 coins int 11.15 样例 dfs 钞票 杨辉三角 dp


递归输出数字三角形

【问题描述】
  输出一个n行的与样例类似的数字三角形,必须使用递归来实现
【输入格式】
  一个正整数数n,表示三角形的行数
【输出格式】
  输出一个与样例类似的n行的数字三角形,同一行每两个数之间用一个空格隔开即可(图中只是为防止题面格式化而用’_'代替空格)
【样例输入】
4
【样例输出】
___1
__2_3
_4_5_6
7_8_9_10
【数据规模和约定】
  n<=20
【解题思路】
  看完题目顺着思路想可能会去思考如何通过n判断输出多少个空格?每一行应该输出多少个数字?此时就会想到,如果能先输出最后一行,那我就不用再数要输多少个空格了。这样就很容易能想到用递归做。
  dfs的思想:一条路走到黑,直到走不了才会选择回头,然后重新选择一条路。
以n=4为例:
在这里插入图片描述
有阴影的格子是不需要输出空格的。
从最后一行开始,每走完一行step退后一步,再继续走。

#include <iostream>
using namespace std;

int n, cnt = 1;

void dfs(int x) {
	if (x == 1) {							//dfs结束的标志
		for (int i = 0; i < n - x; i ++ ) {
			cout << " ";
		}
		cout << cnt ++ << endl;
		return;								//返回上一级的dfs函数
	}
	dfs(x - 1);																
	
	//这两个for循环即能输出一行
	for (int i = 0; i < n - x; i ++ )     //输出前面的空格
		cout<<" ";
	for (int i = 0; i < x; i ++ )		  //输出数,别忘了两个数之间用空格隔开
		cout << cnt++ <<" ";
	
	cout << endl;   					 //回车进入下一行
}

int main() {
	cin >> n;
	dfs(n);
	return 0;
}

蓝桥杯第十二届省赛真题-杨辉三角形

【问题描述】
  下面的图形是著名的杨辉三角形:
在这里插入图片描述
  如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
 1,1,1,1,2,3,1,3,3,1,1,4,6,4……
  给定一个整数N,请你输出数列中第一次出现N是在第几个数?
【输入格式】
  输入一个整数N
【输出格式】
  输出一个整数代表答案
【样例输入】
  6
【样例输出】
  13
【评测用例规模与约定】
  对于20%的评测用例,1 <= N <= 10
  对于所有评测用例,1 <= N <= 10^9

【解题思路】

杨辉三角有两个特点:
  1. 对角线和第一列的值全是1(假设它是一个直角三角形,这样比较好算)
  2. 从第三行开始,每一个值都是它的上一个和上一个的前一个值相加而得,即:a[i][j]=a[i-1][j-1]+a[i-1][j]

求解整数N第一次出现在第几个,只需要在计算杨辉三角数的时候加一个判断和计数器,看一下是否等于N,如果是,就可以输出计数器的值。
  于是我们可以比较轻松的写出代码:

#include <iostream>
using namespace std;

long Tri(int r, int c){					//r和c分别是行和列
	return (c == 1 || c == r)? 1 : Tri(r-1,c-1) + Tri(r-1,c);     
}

int main(){
	int n,a[100][100];		            //这里数组的范围定义太大会出问题,所以先来个100*100的二维数组
	cin >> n;
	int cnt = 1;						//从1开始计数
	for(int i = 1; i <= n; i++){
		for(int j = 1;j <= i; j++){
			a[i][j] = Tri(i,j);
			if(a[i][j] == n){			 //判断是否等于n
				cout << cnt;
				break;          		 //输出第一个满足的即可 
			}
			cnt++;					     //每计算完一个数,计数器+1
		}
	}
	return 0;
}

其中Tri函数写的非常巧妙,出自这篇“博客”。它等效于:

//杨辉三角型代码
for(int i=0; i<n; i++){
	a[i][1] = 1;
	a[i][i] = 1;
}
for(int i=3; i<n; i++){
	for(int j=2; j<i-1; j++){
		a[i][j] = a[i-1][j-1] + a[i-1][j];
	}
}
//这是我之前的代码

但是!这个代码花费的空间实在太多了!!

在蓝桥杯系统上跑会出现“运行超时”,而且只有20分!

尝试将数组换成vector容器也会出现空间不足的报错
这意味着这个思路是不可行的
于是我找到了一个非常巧妙并且值得学习的解法:

找规律 + 二分 - 杨辉三角形 - 第十二届蓝桥杯省赛第一场C++B组

(里面的代码在系统上跑可以跑到完美的分数)

用最少的钞票组成指定的金额

【问题描述】
  已知不同面值的钞票,求如何用最少数量的钞票组成某个金额,求可以使用的最少钞票数量。如果任意数量的已知面值都无法组成该金额,则返回-1。
【输入格式】
  第一行输入一个整数n
  第二行依次输入n个整数,代表钞票的面额
  第三行输入目标金额
【输出格式】
  输出一个整数代表答案
【样例输入】
  5
  1 2 5 7 10
  14
【样例输出】
  2
【解题思路】
  最简单的方法是用贪心算法:每次优先选最大的面值,但是放在这题显然不合理——根据贪心算法14金额可由10、2、2组成,一共需要三张,而实际上,只需要两张7元即可解决问题!贪心只能解决一小部分问题,因此对于这题,我们可以使用dp(动态规划)。

dp的思想:分治,在子问题中选最优,从而推算出当前问题的最优解。
举个例子:走楼梯。走楼梯有两种方法:一次走一层和一次走两层,问你走到第 i 层有多少种走法?
       用dp的思想,要计算到第 i 层就要知道第 i -1 层和第 i - 2 层的走法,因为它们有多少种走法直接确定了第 i 层的走法数,以此类推,要知道第 i - 1 层的走法就必须要知道第 i - 2 层和第 i - 3层的走法…………
       因此可以得知dp动态转移方程为:dp[ i ] = dp[ i - 1 ] + dp [ i - 2 ]

那么如何将dp思想运用到这道题目中呢?
两种情况:
  1、如果目标金额刚好与其中一个面值相等,那么使用最少钞票数就是1(最好的情况)
  2、否则,计算面值能够组成目标金额的所有组合,求使用的最小钞票数。(遍历,求最小:min方法)
  如:14可由10+4组成,而4又可分为2+2,故14的其中一种解法是:10、2、2(例子不代表最佳)
  动态转移方程:dp[ i ] = min( dp[ i - 1] , dp[ i - 2 ] . dp[ i - 5 ] . dp[ i - 7 ] . dp[ i - 10 ] ) + 1
  在这里插入图片描述

其中 dp[ i ]中存储金额1 ~ i 的最优解
coins数组存储钞票面值

int Coinproblem(vector<int>& coins, int amount){
	vector<int> dp;
	for(int i = 1; i <= amount; i++){		//初始化dp数组 
		dp.push_back(-1);
	}
	dp[0] = 0;								//特殊:金额0的最优解为0 
	for(int i = 1; i <= amount; i++){		//求i~amount金额的最优解,并存进dp数组 
		for(int j = 0; j < coin.size(); j++){
			if(i - coins[j] >= 0 && dp[i-coins[j]] != -1){
				if(dp[i] == -1 || dp[i] > dp[i-coins[j]]+1){
					dp[i] = dp[i-coins[j]]+1;
				}
			}
		}
	}
	return dp[amount];
}

两个if条件语句的意思:
1、i - coins[ j ] >= 0 :钞票面值必须小于等于金额
  dp[ i - coins[ j ] ] != -1 :必须有此面值的钞票
2、dp[ i ] == -1:无此面值的钞票
  dp[ i ] > dp [ i - coins[ j ] ] + 1 :判断组合是否比原组合数更小。其实这句结合下面一句dp[ i ] = dp[ i -coins [ j ] ] + 1就类似于min方法,把大的用小的替换掉。

标签:输出,coins,int,11.15,样例,dfs,钞票,杨辉三角,dp
来源: https://blog.csdn.net/ihavea_bug/article/details/121353601

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有