N诺刷题C++

有向树形态

求N个结点能够组成的二叉树的个数
定义f(0)= 1
当只有一个节点时,只会生成一种类型的二叉树,记做f(1)= 1
当有两个节点时,首先固定一个节点(即固定根节点),剩下一个节点可以排放的位置为1= 1+0 = 0+1[即左边一个节点右边0个节点或者左边0个节点右边1个节点]记做f(2)= f(1)f(0) + f{0}f(1) = 2
当有三个节点,首先固定根基点,剩下3-1=2个节点的安放位置:2= 2
0 + 1
1 + 0*2 记做f(3)= f(2)*f(0) + f(1)*f(1) + f(0)*f(2) = 2 + 1 + 2 = 5

当有n个节点时,也是首先固定下根节点,剩下n-1个节点,可以如下排放:n-1= (n-1)*0 + (n-2)*1 + (n-3)2 + … + 0(n-1)记做f(n)= f(n-1)*f(0) + f(n-2)*f(1) + f(n-3)*f(2) + f(n-4)*f(3) + …f(0)*f(n-1)

#include<iostream>
using namespace std;
int main(){
	int n;
	cin >> n;
	if(n < 2){
        cout << n;
	}
	else{
        long long dp[n+1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 2 ; i <= n ; i++){
            long long res = 0;
            for(int j = 0 ; j < i ; j++){
                res = res + dp[j] * dp[i-1-j];
            }
            dp[i] = res;
        }
        cout << dp[n];
	}
	return 0;
}

解一元一次方程

解方程,给定一个字符串,代表一个一元一次方程。如果有解求解,输出格式“x=数字“,如果解的个数无穷,输出 “infinite solutions”。如果没有解输出“no solution”,字符串长度不超过 256 。
这道题,我也没想出来什么好办法,就用if写吧

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	string str;
	cin >> str;
	int flag = 1;
	int a = 0, b = 0;
	int i = 0;
	while(str[i] != '='){
        if(str[i] == 'x'){
            b = b + flag;
        }
	    int temp = 0;
        while(str[i]>='0' && str[i]<='9'){
            temp = temp * 10 + str[i] - '0';
            i++;
        }
        if(str[i] != 'x'){
            a = a + flag * temp;
        }
        else{
            b = b + flag * temp;
            i++;
        }
        if(str[i] == '-'){
            flag = -1;
        }
        else{
            flag = 1;
        }
        if(str[i] == '='){
            break;
        }
        i++;
	}
	flag = -1;
	while(i < str.size()){
        if(str[i] == 'x'){
            b = b + flag;
        }
	    int temp = 0;
        while(str[i]>='0' && str[i]<='9'){
            temp = temp * 10 + str[i] - '0';
            i++;
        }
        if(i == str.size() || str[i] != 'x'){
            a = a + flag * temp;
        }
        else{
            b = b + flag * temp;
            i++;
        }
        if(str[i] == '-'){
            flag = 1;
        }
        else{
            flag = -1;
        }
        i++;
	}
	if(a==0 && b==0){
        cout << "infinite solutions";
	}
	else if(b==0){
        cout << "no solution";
	}
	else{
        cout << "x=" << (-a)/b;
	}
	return 0;
}

整数拆分

一个整数总可以拆分为2的幂的和,例如: 7=1+2+4 7=1+2+2+2 7=1+1+1+4 7=1+1+1+2+2 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 总共有六种不同的拆分方式。 再比如:4可以拆分成:4 = 4,4 = 1 + 1 + 1 + 1,4 = 2 + 2,4=1+1+2。 用f(n)表示n的不同拆分的种数,例如f(7)=6. 要求编写程序,读入n(不超过1000000),输出f(n)%1000000000。

对于一个数字 n,如果 n 是奇数,那么 n 的所有组合方式中一定包含一个 1,那么它和 n-1 的组合方式种数相同,dp[n] = dp[n-1];

如果 n 是偶数,那么它的组合方式中可能有 1,也可能没有 1,有 1 的组合方式有 dp[n - 1] 种,没有 1 的组合方式有 dp[n/2] 种,因为偶数组合方式除以 2 后的组合方式其实是一样的,dp[n] = dp[n-1] + dp[n/2]

#include<iostream>
using namespace std;
int main(){
	int n;
	while(cin >> n){
        if(n < 2){
            cout << n << endl;
        }
        else{
            long dp[n+1];
            dp[1] = 1; 
            for(int i = 2 ; i <= n ; i++){
                if(i%2 == 0){
                dp[i] = (dp[i-1] + dp[i/2])%1000000000;
                }  
               else{
                dp[i] = dp[i-1];
                }
            }
            cout << dp[n]<< endl;
        }
	}
	return 0;
}

最小邮票数

有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int main(){
	int n, k;
	cin >> n >> k;
	int num[k];
	for(int i = 0 ; i < k ; i++){
        cin >> num[i];
	}
	int dp[n+1];
	for(int i = 0 ; i <= n ; i++){
        dp[i] = 1000;
	}
	dp[0] = 0;
	for(int i = 0 ; i < k ; i++){
        for(int j = n ; j >= num[i] ; j--){
            if(dp[j-num[i]] != 1000)
                dp[j] = min(dp[j], dp[j-num[i]]+1);
        }
        for(int j = 0 ; j <= n ; j++){
            cout << dp[j] << ' ';
        }
        cout << endl;
	}
	if(dp[n] == 1000){
        cout << 0;
	}
	else{
        cout << dp[n];
	}
	return 0;
}

过河卒

棋盘上 A 点有一个过河卒,需要走到目标 B 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A 点 (0, 0)、B 点 (n, m),同样马的位置坐标是需要给出的。

思想还是之前的动态规划,只要避开马和马会经过的点就好了。

#include<iostream>
using namespace std;
int main(){
	int bx, by, mx, my;
	while(cin >> bx >> by >> mx >> my){
        long long bp[by+1][bx+1];
        for(int i = 0 ; i <= by ; i++){
            for(int j = 0 ; j <= bx ; j++){
                if(i==0 || j==0)
                    bp[i][j] = 1;
                else
                    bp[i][j] = 0;
            }
        }
        for(int i = 1 ; i <= by ; i++){
            for(int j = 1 ; j <= bx ; j++){
                if((abs(i-my)==1 && abs(j-mx)==2) || (abs(i-my)==2 && abs(j-mx)==1)||(i==my && j==mx)){
                    bp[i][j] = 0;
                }
                else{
                    bp[i][j] = bp[i-1][j] + bp[i][j-1];
                }
            }

        }
        cout << bp[by][bx] << endl;
	}
	return 0;
}

路径计数2

一个N×N的网格,你一开始在(1,1),即左上角。每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N),即右下角有多少种方法。
但是这个问题太简单了,所以现在有M个格子上有障碍,即不能走到这M个格子上。

注意当这个障碍点在边界上,即上边界或是左边界,在它之后的位置点路径方法都为0

#include<iostream>
using namespace std;
int main(){
	int n, m;
	while(cin >> n >> m){
        long long bp[n+1][n+1];
        long long matrix[n+1][n+1];
        for(int i = 0 ; i <= n ; i++){
            for(int j = 0 ; j <= n ; j++){
                matrix[i][j] = 1;
                bp[i][j] = 0;
            }
        }
        int x, y;
        for(int i = 0 ; i < m ; i++){
            cin >> x >> y;
            matrix[y][x] = 0;
        }
        for(int i = 0 ; i <= n ; i++){
            **if(matrix[1][i] != 0)
                bp[1][i] = 1;
            else
                break;
        }
        for(int i = 0 ; i <= n ; i++){
            if(matrix[i][1] != 0)
                bp[i][1] = 1;
            else
                break;
        }
        for(int i = 2 ; i <= n ; i++){
            for(int j = 2 ; j <= n ; j++){**
                if(matrix[i][j] == 0){
                    bp[i][j] = 0;
                }
                else{
                    bp[i][j] = bp[i-1][j] + bp[i][j-1];
                }
            }

        }
        cout << bp[n][n] << endl;
	}
	return 0;
}

Windy数

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?

数位dp,现在还有点不太理解

#include<iostream>
#include<string.h>
using namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000005
#define vec vector<ll>
#define P pair<int,int>

int dp[15][10];//dp[i][j]:位数为i,最高位为j时最多有多少windy数

//统计[1,x)区间内的windy数
int cal(int x) {
	int a[11], len = 0;
	while (x > 0) {
		a[++len] = x % 10;
		x /= 10;
	}
	int sum = 0;
	//1:统计位数比x少的
	for (int i = 1; i < len; i++)
		for (int j = 1; j < 10; j++)//注意这里从1开始,最高位不能为0!
			sum += dp[i][j];
	//2:统计位数和x一样,但是首位比x小的,同样最高位不能为0
	for (int i = 1; i < a[len]; i++)
		sum += dp[len][i];
	//3:统计位数与x一样,首位也一样的,那么之前的每一位加上限制a[i]
	for (int i = len - 1; i >= 1; i--) {
		for (int j = 0; j < a[i]; j++)  //注意该位的限制,由于不是最高位,可以从0开始
			if (abs(j - a[i + 1]) >= 2)//该位和上一位满足要求
				sum += dp[i][j];
		if (abs(a[i + 1] - a[i]) < 2)//传入数字连续两位不满足了
			break;
	}
	return sum;
}

int main() {
	memset(dp, 0, sizeof(dp));
	for (int i = 0; i < 10; i++)dp[1][i] = 1;//预处理第一位

	for (int i = 2; i < 11; i++) //遍历每2-10每个位数,1预处理了
		for (int j = 0; j < 10; j++) //遍历这一位的每种可能数字
			for (int k = 0; k < 10; k++) //遍历上一位的每种可能数字
				if (abs(k - j) >= 2) //相邻数字之差大于2
					dp[i][j] += dp[i - 1][k];
	int a, b;
	while (cin >> a >> b) {
		if (a > b)swap(a, b);
		cout << cal(b + 1) - cal(a) << endl;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猫头丁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值