考试整理

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);                //输出前序遍历的路径
}
原文地址:https://www.cnblogs.com/gongcheng456/p/10998433.html