计算每个节点的子树的和
示例:1 2 4 -1 -1 5 -1 -1 3 6 -1 -1 7 -1 -1所得为
1
/ \
2 3
/ \ / \
4 5 6 7
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAX_N = 10001;
vector<int> tree[MAX_N]; // 存储树结构
int sum[MAX_N]; // 存储每个节点的子树和
// 构建树结构
void buildTree(int node) {
int value;
cin >> value;
if (value == -1) return; // 如果节点为空,直接返回
sum[node] += value; // 将节点值加到节点的子树和中
buildTree(node - 1); // 递归构建左子树
buildTree(node + 1); // 递归构建右子树
}
// 初始化树结构
bool init() {
int value;
cin >> value;
if (value == -1) return false; // 如果节点为空,返回 false 表示输入结束
memset(sum, 0, sizeof(sum)); // 初始化节点的子树和为 0
int root = MAX_N / 2; // 根节点的索引
sum[root] = value; // 将根节点的值加到根节点的子树和中
buildTree(root - 1); // 构建左子树
buildTree(root + 1); // 构建右子树
return true;
}
int main() {
int caseNum = 0;
while (init()) { // 初始化树结构,直到输入结束
int node = 0;
while (sum[node] == 0) node++; // 找到第一个非空节点
cout << "case " << ++caseNum << ":\n" << sum[node++]; // 输出第一个非空节点的子树和
while (sum[node] != 0) cout << " " << sum[node++]; // 输出剩余节点的子树和
cout << "\n\n";
}
return 0;
}
建造房屋
问题描述
小蓝和小桥是两位年轻的建筑师,他们正在设计一座新的城
市。
在这个城市中,有N条街道,每条街道上都有M个位置可
以建造房屋(一个位置只能建造一个房屋)。建造一个房屋的
费用为1元,小蓝和小桥共有K 元的建造预算。
现在,他们想知道,一共有多少种建造方案,满足以下要求:
·在每条街道上,至少建一个房屋。
·建造的总成本不能超过K元。
由于方案数可能很大,他们只需要输出答案对109+7取模
的结果。
输入格式
一行三个整数N,M(1≤N,M≤30)和K(1≤
K≤N·M),分别表示街道数、街道的位置数和预算。
输出格式
一个整数,表示满足条件的建造方案数对109+7取模的结
果。
思路:dp[i][j]
表示在前 i
个地块中建造了 j
栋房子的方案数。
#include <iostream>
#include <algorithm>
#include <cstring> // for memset
using namespace std;
const long long p = 1e9+7;
int main(void) {
int n, m, k;
cin >> n >> m >> k;
long long dp[n + 1][m + 1];
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
dp[i][1] = 1;
for (int j = i; j <= k; j++) {
dp[i][j] += dp[i][j - 1] % p; // 不多建房屋
for (int a = 1; a < min(m, j); a++) { // 再建房屋
dp[i][j] += dp[i - 1][j - a] % p; // 此前的方案数累加
}
}
}
long long ans = 0;
for (int j = 1; j <= k; j++) {
ans += dp[n][j] % p;
ans %= p;
}
cout << ans;
return 0;
}
破损楼梯
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int p = 1e9 + 7;
int main(void){
int n, m;
cin >> n >> m;
int dp[n + 1];
int broken[m + 1];
memset(dp, 0, sizeof(dp));
memset(broken, 0, sizeof(broken));
int x;
for(int i = 1; i <= m; i++){
cin >> x;
broken[x] = 1;
}
dp[0] = 1;
dp[1] = !broken[1];
for(int i = 2; i <= n; i++){
if(broken[i]) {
dp[i] = 0; // 如果第i个街道被损坏,则不能建造房屋,方案数为0
} else {
dp[i] = (dp[i - 1] + dp[i - 2]) % p; // 否则按照动态规划递推关系计算方案数
}
}
cout << dp[n];
}
括号生成
给出括号数,输出所有括号组成方案
最优解
class Solution {
public:
vector<string> generateParenthesis(int n) {
if (n == 0) return {};
if (n == 1) return { "()" };
vector<vector<string>> dp(n+1);
dp[0] = { "" };
dp[1] = { "()" };
for (int i = 2; i <= n; i++) {//总括号个数
for (int j = 0; j <i; j++) {//分括号个数
for (string p : dp[j])//遍历dp[j]中每个字符串
for (string q : dp[i - j - 1]) {//所有括号减去自行添加的和已经遍历到的括号
string str = "(" + p + ")" + q;
dp[i].push_back(str);
}
}
}
return dp[n];
}
};
暴力解
class Solution {
bool valid(const string& str){
int balance=0;
for(char c:str){
if(c=='(')++balance;
else --balance;
if(balance<0)return false;
}
return balance==0;
}
void generate_all(string& current,int n,vector<string>& result){
if(n==current.size()){
if(valid(current)){
result.push_back(current);
}
return;
}//方案可行
current+='(';
generate_all(current,n,result);
current.pop_back();//回到前一个状态
current += ')';
generate_all(current, n, result);
current.pop_back();
}
public:
vector<string> generateParenthesis(int n) {
vector<string>result;
string current;
generate_all(current,n*2,result);
return result;
}
};
地图
问题描述 传说,在蓝桥王国中一个极其神秘的森林。这个森林的起点在(1,1),终点在(n,m)。在你进入这个森岭后,每次你只可以向下或者向右走,由于森岭的神秘力量,至多只可以改变k次方向。 小蓝现在想知道,一共有多少种方案可以从(1,1)进入然后从 (n,m)走出。
数据保证至少存在一种方案。 输入格式 第1行包含三个正整数n,m,k,分别表示地图的规模和可以改变方向的次数。 第2到n+1行包含m个字符,表示地图上该位置的信息,用.表示空地,#表示石头无法通行,保证起点和终点不为石头。 输出格式 输出共1行,包含1个整数,表示方案数。 样例输入 331 .#. 样例输出 2 评测数据规模 对于所有评测数据,1≤n,m≤100,1≤k≤5。 运行限制 语言 最大运行时间 最大运行内存 C++ 3s 512M C 3s 512M Java 5s 512M Python3 10s 512M
思路:与八皇后有点像,因为只能向右向下,不会回到原来的位置,无需记录走过vis。如果要打印路径用f[x][y][d][step]记录位置、方向和步数。
其实我感觉if (f[x][y][d][step]) return f[x][y][d][step];改node,含位置、是否访问过、方向和步数会更好吧,这个不太理解
#include <bits/stdc++.h>
using namespace std;
const int N = 101;
int n, m, k;
char s[N][N];
int f[N][N][2][6];
int dx[] = {0, 1}, dy[] = {1, 0}; // 方向数组
int dfs(int x, int y, int d, int step) {//xy坐标,d走的方法,step剩余步数
if (x > n || y > n) return 0; // 越界检查
if (s[x][y] == '#') return 0; // 障碍物检查
if (step > k) return 0; // 方向变换次数检查
if (x == n && y == m) return 1; // 达到终点,return 1代表成功
if (f[x][y][d][step]) return f[x][y][d][step]; // 记忆化搜索到原来走过的路线直接返回
int res = 0;//res 会累加上从下一步开始找到的满足条件的路径数量。
for (int i = 0; i < 2; i++) { // 遍历两个方向
res += dfs(x + dx[i], y + dy[i], i, step + (i != d));//倒数第二次加上最后一次,依次递归
//step + (i != d)表示下一步的方向变换次数,如果当前方向i和上一步的方向d不同,则方向变换次数加1。
}
return f[x][y][d][step] = res;//f[x][y][d][step]记录为了记忆化搜索
}
int main() {
ios::sync_with_stdio(false);//提高性能
cin.tie(nullptr);//提高性能
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
cin >> s[i] + 1;
int ans = 0;
if (s[1][2] != '#') ans += dfs(1, 2, 0, 0);//最开始走的两种情况
if (s[2][1] != '#') ans += dfs(2, 1, 1, 0);
cout << ans << "\n";
return 0;
}