T1 FBI树
不得不说,这个题目考的就是树的遍历的方法
只要会建树就可以了
还有就是要注意后序遍历(简单点说就是左右头)
#include <bits/stdc++.h> using namespace std; char s[1025]; //对字符串进行操作 (先设出来) inline void maketree(int x, int y) //建树(没错,我们要有一定的建树QwQ) { if (y > x) //放在前面保证了后序遍历 { maketree(x, (x + y) / 2); //递归 maketree((x + y + 1) / 2, y); } int B = 1, I = 1; for (int i = 0; i <= y - x; i++) //进行操作 { if (s[x + i] == '1') { B = 0; } if (s[x + i] == '0') { I = 0; } } if (B) //输出 { cout << "B"; } else if (I) { cout << "I"; } else { cout << "F"; } } int main() { int n; cin >> n; cin >> s; maketree(0, (1 << n) - 1); return 0; }
T2 医院设置
其实是一道挺裸的Floyd了(不会Floyd的进呗)
还要记录并比较所枚举的每个点作为根的总距离
输出最小的
主要困难在于双向边的处理(来回的权值并不一样)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define maxn 0x3f3f3f3f int s[101], dis[101][101], sum; int n, l, r; using namespace std; int main() { cin >> n; memset(dis, maxn, sizeof(dis)); for (int i = 1; i <= n; i++) { dis[i][i] = 0; cin >> s[i]; cin >> l >> r; if (l >= 0) //注意双向边 { dis[i][l] = 1; dis[l][i] = 1; } if (r >= 0) //注意双向边 { dis[i][r] = 1; dis[r][i] = 1; } } for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { if (i != k) { for (int j = 1; j <= n; j++) { if (i != j && k != j && dis[i][j] > dis[i][k] + dis[k][j]) { dis[i][j] = dis[i][k] + dis[k][j]; //求最短路 } } } } } int minn = maxn; for (int i = 1; i <= n; i++) { sum = 0; for (int j = 1; j <= n; j++) { if (i != j && dis[i][j] != -1) { sum += s[j] * dis[i][j]; //求总的代价 } } if (minn > sum) //最小代价 { minn = sum; } } cout << minn; return 0; }
T3 加分二叉树
当我看到这个题的时候我发现:模拟真的很重要啊QwQ
加分最大,所以就有了最优子阶段。我们可以枚举根来更新最大值。中序遍历有个特点,再中序遍历这个序列,某个点左边的序列一定是这个点的左子树,右边的序列,一定在这个点的右子树。
然后再进行来回的操作
代码运用了区间DP(看起来还行)
#include <iostream> using namespace std; int n; int d[31]; long long dp[31][32]; //dp[i][j] -> answer in [i,j) 左闭右开(important) int w[31][32]; void dfs(int l, int r) { cout << w[l][r] << ' '; //满足前序遍历 if (w[l][r] > l) dfs(l, w[l][r]); //递归 if (w[l][r] + 1 < r) dfs(w[l][r] + 1, r); //递归 } int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> dp[i][i + 1], dp[i][i] = 1, w[i][i + 1] = i; for (int l = 2; l <= n; l++) //枚举区间 { for (int i = 1; i + l <= n + 1; i++) { int j = i + l; for (int k = i; k < j; k++) //枚举根结点 { if (dp[i][k] * dp[k + 1][j] + dp[k][k + 1] > dp[i][j]) { dp[i][j] = dp[i][k] * dp[k + 1][j] + dp[k][k + 1]; //找到最优的方案转移 w[i][j] = k; //需要保存根结点 } } } } cout << dp[1][n + 1] << endl; //直接输出最大的价值(肯定是1--n无疑了) dfs(1, n + 1); //输出前序遍历的路径 }