博客
关于我
codeforces 1286B Numbers on Tree
阅读量:744 次
发布时间:2019-03-21

本文共 4656 字,大约阅读时间需要 15 分钟。

给定一棵具有n个节点的树,每个节点都有一个权值。数组c[i]表示节点i的子树中权值比i小的点的个数。目标是根据c数组构造出符合要求的每个节点的权值,如果无法构造则输出“NO”。

首先,检查数组c是否满足条件:

  • 对于每个节点i,确保c[i] <= sz[i] - 1,其中sz[i]是子树i的大小。如果有任何一个节点不满足这一条件,直接输出“NO”。
  • 如果c数组有效,接下来需要构造权值。可以使用DFS或BFS的方式从根节点开始赋值:

    • 从根节点开始,逐层赋予节点序号1到n。
    • 在处理每个节点u时,确定需要赋予的权值是c[u] + 1,再从可用的数中选择最小的剩余数。

    这种方法确保每个节点的子树中有恰好c[i]个权值比它小的点,从而构造出符合c数组的权值序列。

    代码实现

        树权值构造问题    

    树权值构造问题

    题意:
    一棵树,有n个节点,每个节点都有一个权值,定义数组c【i】为 i 的子树中权值比 i 小的点的个数。现在告诉我们数组c的值,让我们构造出每个点的权值满足c数组。如果不能构造,则输出no。
    解题思路:
    首先,我们需要检查c数组是否满足条件。对于每个节点i,如果c[i] 大于子树i的大小减一(即c[i] > sz[i] - 1),则直接无法构造,输出"NO"。 如果c数组有效,我们可以采用特定的赋值策略: - 按照从根到叶子的顺序赋予节点权值,不断递归或迭代地为每个节点找到一个合适的数。 - 具体而言,我们可以使用一个数组w来存储每个节点的权值,并利用标记数组vis来跟踪已使用的数值。 - 在赋值时,从可用数中选择c[u]+1,并处理每个子节点,确保满足c数组的条件。
    代码实现:
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define iss std::ios::sync_with_stdio(false) using namespace std; typedef long long ll; const int MAXN = 1e5 + 5; int n; int c[2005]; int head[2005]; int cnt = 0; int fa[2005]; int sz[2005]; int flag = 0; int vis[2005]; int w[2005]; struct node { int to; int next; } e[4005]; void add(int u, int v) { e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++; } void dfs(int u, int f) { sz[u] = 1; for (int i = head[u]; i != -1; i = e[i].next) { int v = e[i].to; if (v == f) continue; dfs(v, u); sz[u] += sz[v]; } if (c[u] > sz[u] - 1) flag = 1; } void solve(int u, int f) { int temp = c[u] + 1; for (int i = 1; i <= n; i++) { if (vis[i] == 0) { if (temp == 1) { w[u] = i; vis[i] = 1; break; } else if (temp-- > 1) { temp--; } } } for (int i = head[u]; i != -1; i = e[i].next) { if (e[i].to != f) solve(e[i].to, u); } } int main() { int root = 1; for (int i = 1; i <= n; i++) { cin >> fa[i] >> c[i]; if (fa[i] == 0) { root = i; } else { add(fa[i], i); } } sz[root] = 0; for (int i = root; i <= n; i++) { if (fa[i] == 0) { sz[i] = 1; sz[root]++; } } if (flag) { cout << "NO"; return; } solve(root, 0); for (int i = 1; i <= n; i++) { if (vis[i] == 0) { cout << "NO"; return; } } for (int i = 1; i <= n; i++) { if (!vis[i]) { continue; } for (int v = root; v <= n; v++) { int total = 0; for (int u = v; u != -1; u = e[u].next) { if (e[u].to != v) total++; else break; } if (c[v] != total) { cout << "NO"; return; } } } for (int i = 1; i <= n; i++) { cout << w[i] << " "; } return; }
    要解决这种树结构中的权值构造问题,可以按照以下步骤进行:1. **输入处理**: - 读取输入数据,构建树的邻接表,并确定树的根节点。2. **检查c数组有效性**: - 递归计算每个节点的子树大小,并检查每个节点的c[i]是否满足0 ≤ c[i] < sz[i]。如果有任何节点不满足,直接输出“NO”。3. **构造权值**: - 从根节点开始,启用DFS或BFS赋予权值,确保每个节点的权值满足c数组的要求。 - 使用一个数组vis来跟踪已使用的权值数目,按顺序为每个节点确定合适的数值。4. **验证结果**: - 最后,检查构造后的权值是否满足所有节点的c数组条件,如果满足,输出权值数组w;否则输出“NO”。### 代码示例```cpp#include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define iss std::ios::sync_with_stdio(false)using namespace std;typedef long long ll;const int MAXN = 1e5 + 5;int n;int c[2005];int head[2005];int cnt = 0;int fa[2005];int sz[2005];int flag = 0;int vis[2005];int w[2005];struct node { int to; int next;} e[4005];void add(int u, int v) { e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++;}void dfs(int u, int f) { sz[u] = 1; for (int i = head[u]; i != -1; ++i) { int v = e[i].to; if (v == f) continue; dfs(v, u); sz[u] += sz[v]; } if (c[u] > sz[u] - 1) { flag = 1; }}void solve(int u, int f) { int temp = c[u] + 1; for (int i = 1; i <= n; ++i) { if (vis[i] == 0) { if (temp == 1) { w[u] = i; vis[i] = 1; break; } else if (temp-- > 1) { temp--; } } } for (int i = head[u]; i != -1; ++i) { int v = e[i].to; if (v == f) continue; solve(v, u); }}int main() { iss; read(gamma); for (int i = 1; i <= n; ++i) { fa[i] = 0; c[i] = 0; } for (int i = 1; i <= n; ++i) { cin >> fa[i] >> c[i]; if (fa[i] == 0) { sz[fa[i]]++; sz[i] = 1; } else { add(fa[i], i); } } sz[root] = 0; for (int i = root; i <=n; i++) { if (fa[i] == 0) sz[i]=1; } if (flag) { cout << "NO"; return; } solve(root, 0); for (int i=1; i<=n; ++i){ if (vis[i] == 0) { cout << "NO"; return; } } for (int i=1; i<=n; ++i){ for (int v=root; v<=n; ++v){ int total=0; for (int u=v; u!=-1; u=e[u].next){ if (u==v) break; total++; } if (c[v] != total) { cout << "NO"; return; } } } for (int i=1; i<=n; ++i){ cout << w[i] << " "; } return;}

    代码解释

    • 输入处理:读取数据并构建树的邻接表,确定根节点。
    • 子树大小计算:使用DFS计算每个节点的子树大小sz[u]。
    • c数组检查:确认每个节点的c[i]是否在有效范围内。
    • 权值赋值:从根节点开始,使用特定顺序和策略将权值1到n合理分配。
    • 验证构造结果:确保所有节点的c[i]都满足条件,最终输出权值或“NO”。

    通过这种方式,可以有效构造或判断满足条件的树权值问题,确保正确性和效率。

    转载地址:http://rjxgz.baihongyu.com/

    你可能感兴趣的文章
    MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
    查看>>
    MYSQL8.0以上忘记root密码
    查看>>
    Mysql8.0以上重置初始密码的方法
    查看>>
    mysql8.0新特性-自增变量的持久化
    查看>>
    Mysql8.0注意url变更写法
    查看>>
    Mysql8.0的特性
    查看>>
    MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
    查看>>
    MySQL8修改密码的方法
    查看>>
    Mysql8在Centos上安装后忘记root密码如何重新设置
    查看>>
    Mysql8在Windows上离线安装时忘记root密码
    查看>>
    MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
    查看>>
    mysql8的安装与卸载
    查看>>
    MySQL8,体验不一样的安装方式!
    查看>>
    MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
    查看>>
    Mysql: 对换(替换)两条记录的同一个字段值
    查看>>
    mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
    查看>>
    MYSQL:基础——3N范式的表结构设计
    查看>>
    MYSQL:基础——触发器
    查看>>
    Mysql:连接报错“closing inbound before receiving peer‘s close_notify”
    查看>>
    mysqlbinlog报错unknown variable ‘default-character-set=utf8mb4‘
    查看>>