博客
关于我
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/

    你可能感兴趣的文章
    mysql 为某个字段的值加前缀、去掉前缀
    查看>>
    mysql 主从
    查看>>
    mysql 主从 lock_mysql 主从同步权限mysql 行锁的实现
    查看>>
    mysql 主从互备份_mysql互为主从实战设置详解及自动化备份(Centos7.2)
    查看>>
    mysql 主从关系切换
    查看>>
    MYSQL 主从同步文档的大坑
    查看>>
    mysql 主键重复则覆盖_数据库主键不能重复
    查看>>
    Mysql 事务知识点与优化建议
    查看>>
    Mysql 优化 or
    查看>>
    mysql 优化器 key_mysql – 选择*和查询优化器
    查看>>
    MySQL 优化:Explain 执行计划详解
    查看>>
    Mysql 会导致锁表的语法
    查看>>
    mysql 使用sql文件恢复数据库
    查看>>
    mysql 修改默认字符集为utf8
    查看>>
    Mysql 共享锁
    查看>>
    MySQL 内核深度优化
    查看>>
    mysql 内连接、自然连接、外连接的区别
    查看>>
    mysql 写入慢优化
    查看>>
    mysql 分组统计SQL语句
    查看>>
    Mysql 分页
    查看>>