N诺刷题C++
Posted 猫头丁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了N诺刷题C++相关的知识,希望对你有一定的参考价值。
有向树形态
求N个结点能够组成的二叉树的个数
定义f(0)= 1
当只有一个节点时,只会生成一种类型的二叉树,记做f(1)= 1
当有两个节点时,首先固定一个节点(即固定根节点),剩下一个节点可以排放的位置为1= 1+0 = 0+1[即左边一个节点右边0个节点或者左边0个节点右边1个节点]记做f(2)= f(1)f(0) + f0f(1) = 2
当有三个节点,首先固定根基点,剩下3-1=2个节点的安放位置:2= 20 + 11 + 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;
以上是关于N诺刷题C++的主要内容,如果未能解决你的问题,请参考以下文章