武汉大学“华为杯”补题

贪心 + 递归

D-和谐之树_"华为杯" 武汉大学21级新生程序设计竞赛 (nowcoder.com)

这题我在做的时候根本没有理解清楚题意,也可能是受到样例解释的影响? 

就比如n=10的时候,我就认为最大的节点编号是21,因为[1,10]一共可以构造21个子区间,所以最大的节点编号就是21,如图:

 图中共有21个区间,但如果我们从做左到右,从上到下,把整棵树看做一个完全二叉树,其中区间[7,7]是最后一个区间,那么在完全二叉树当中,[7,7]就是第25个区间了,而题目的意思就是让我们让我们把给定的区间[1,n]展开成一棵树,然后把这棵树放在一个完全二叉树当中,计算这棵树在完全二叉树当中最大的节点编号!

由于完全二叉树的节点编号从左到右,从上到下是依次递增的,所以说,我们希望,这个最大节点位于最下一层的最右边的节点(上下深度的优先级更大)

并且,我们能得知这个最大节点是在左子树还是在右子树中,由于上下的优先级肯定是大于左右的。

  • 所以当左子树的深度小于右子树时,肯定是右子树,当右子树深度小于左子树时,肯定是左子。
  • 难点在于当深度相等的时候,我们应该选择哪一个区间。我们知道,在完全二叉树中,如果根节点值为root,那么左孩子就是2*root,右孩子就是2*root+1,显然右边的比左边要大,并且,如果我们选择了右边,那么在深度相同的时候,右边的本来就比左边大。(显而易见的事情)

现在让我们回顾一下递归的步骤

  1. 递归函数的功能:build(l, r, id)求给定区间[l,r],根节点编号为id时这个区间划分到完全二叉树的最大节点编号。
  2. 递归结束的条件:l = r,此时不能再划分区间,递归结束。
  3. 递归的转移:选择左区间:build(l, mid, id << 1);选择右区间:build(mid + 1, r, id << 1
     | 1)
#include <iostream>
#include <cstring>
#include <algorithm>

#define int long long

using namespace std;

int get_depth(int d)//d表示区间长度
{
    int depth = 0;
    while(d != 1)//当区间长度为1时不可在划分
    {
        d = (d + 1) >> 1;//每次划分保留左侧区间长度
        //因为mid是下取整,所以左侧区间长度肯定大于右侧区间长度
        //所以我们每次保留左侧区长度都就行了
        depth ++ ;
    }
    return depth;
}

int build(int l, int r, int id)
{
    if(l == r)//递归结束
    {//此时区间不可以再划分
        return id;//当前的id值就是最大值
    }
    //否则,二分一下左右区间,先看谁的深度更大
    int mid = l + r >> 1;
    int depth_left = get_depth(mid - l + 1);
    int depth_right = get_depth(r - (mid + 1) + 1);
    //递归方程转移
    if(depth_right >= depth_left)
        return build(mid + 1, r, id << 1 | 1);
    else
        return build(l, mid, id << 1);
}


signed main()
{
    int T;
    cin >> T;
    while(T -- )
    {
        int n;  cin >> n;
        cout << build(1, n, 1) << endl;
    }
    
    return 0;
}



贪心 + BFS

J-传闻档案_"华为杯" 武汉大学21级新生程序设计竞赛 (nowcoder.com)

 这道题目的意思很简单,反向建图就行了

但是我一开始想的是按照拓扑序遍历图,但我们知道,拓扑序是不允许出现环的,但这道题目是有环的(样例2就是)

其实直接排序后贪心枚举最大的边就行了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

const int N = 100010;

int n, m;
long long ans, w[N];
pair<int, int> p[N];
vector<int> g[N];
bool st[N];

void bfs(int u)
{
    queue<int> q;
    q.push(u);
    st[u] = true;
    
    while(q.size())
    {
        auto t = q.front(); q.pop();
        int len = g[t].size();
        for(int i = 0; i < len; i ++ )
        {
            int j = g[t][i];
            if(st[j])   continue;
            if(w[j] < w[t])
            {
                w[j] = w[t];
                q.push(j);
                st[j] = true;
            }
        }
    }
}

int main()
{
    cin >> n >> m; 
    
    for(int i = 1; i <= n; i ++ )   
    {
        cin >> w[i];
        p[i] = {w[i], i};
    }
    sort(p + 1, p + n + 1);
    
    while(m -- )
    {
        int a, b;
        cin >> a >> b;
        g[b].push_back(a);
    }
    
    for(int i = n; i >= 1; i -- )
    {
        if(!st[p[i].second])  bfs(p[i].second);    
    }
    
    // for(int i = 1; i <= n; i ++ )   cout << w[i] << " ";
    // cout << endl;
    
    for(int i = 1; i <= n; i ++ )   ans += w[i];
    
    cout << ans << endl;
    
    return 0;
}

posted @ 2022-05-05 08:41  光風霽月  阅读(16)  评论(0编辑  收藏  举报