惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
Jina AI
Jina AI
月光博客
月光博客
博客园 - Franky
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Visual Studio Blog
有赞技术团队
有赞技术团队
V
V2EX
IT之家
IT之家
阮一峰的网络日志
阮一峰的网络日志
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
腾讯CDC
D
DataBreaches.Net
Hugging Face - Blog
Hugging Face - Blog
Martin Fowler
Martin Fowler
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
WordPress大学
WordPress大学
C
Check Point Blog
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog

OhYee 博客

小鹏辅助驾驶测评|OhYee 博客 小鹏非支持手机开启自动解锁|OhYee 博客 使用函数计算实现 301 重定向|OhYee 博客 针对 HTML 内容使用 Ant Design 图片弹框|OhYee 博客 博客进程泄露及僵尸进程解决|OhYee 博客 蓝易云服务器体验|OhYee 博客 SSH 调起本地 VSCode|OhYee 博客 【2022 秋招内推】阿里云后端研发工程师|OhYee 博客 使用函数计算获取 IP 地址信息|OhYee 博客 正确获取客户端 IP/HTTP Header 也可能重复|OhYee 博客 评测 Oculus Quest2 及 BigScreen|OhYee 博客 NextJS 热重载保留状态|OhYee 博客 如何优雅地贴 gist 代码|OhYee 博客 Linux 精细化文件权限|OhYee 博客 VSCode 容器开发环境|OhYee 博客 Clash 的不兼容更新排查|OhYee 博客 Zeek 导出 PCAP|OhYee 博客 记一次 ssh 配置问题|OhYee 博客 Git Commit 规范化工具|OhYee 博客 谈谈《星之卡比-探索发现》|OhYee 博客 VSCode 快捷键绑定 Shell 命令|OhYee 博客 ASN.1 语法及 X.509 证书格式解析解析|OhYee 博客 腾讯企业邮箱忽略 MX 记录发信|OhYee 博客 Chrome/Edge 标签组插件|OhYee 博客 【应届内推】阿里云后端研发工程师|OhYee 博客 损坏的 Typecho 备份处理为 JSON|OhYee 博客 VS Code VIM 插件高效使用|OhYee 博客 SSH 正反向代理|OhYee 博客 Let's Encrypt 根证书过期引发的问题|OhYee 博客 OpenWRT 忽略内核依赖|OhYee 博客
AOJ 795.西瓜理发记(三)|OhYee 博客
2017-03-02 · via OhYee 博客

这是一篇最后编辑于 8 年前 的文章,其内容可能与目前实际情况差异较大,请注意甄别

题目

{% raw %}

{% endraw %} 顺利潜入勺林寺几天后,方丈给了西瓜一个光荣而艰巨的任务——打扫寺庙中的道路。同时给了西瓜一张勺林寺的地图。 西瓜这才知道,勺林寺中总共有n座房子,但道路只有n-1条,这n-1条道路连接了寺中的所有房子,即保证在任何两座房子都能沿着道路抵达。 好在西瓜人缘不错,他知道每座房子中都有个自己的朋友,只要给他们每个人打个电话,让他到自己这里来,顺便把路也扫了,即给某座房子中的朋友打过电话后,可认为从该房子到西瓜所在的位置之间所有的道路都会被打扫干净。 同时西瓜还知道,这n-1条道路中有一些路昨天已经被人打扫过了不需要再打扫一遍。 现在西瓜想知道,自己最少要给多少个朋友打电话才能完成方丈给的任务。 西瓜在编号为1的房子中。

{% raw %}


{% endraw %}

输入包含多组数据
每组数据第一行包含一个n(2?≤?n?≤?10^5),表示有n座房子
之后n-1行,每行三个数字a,b,c表示在房子a和房子b之间有一条路,c等于1表示路已被打扫,c等于2表示路未被打扫。

{% raw %}


{% endraw %}

每组数据输出一个整数k,表示最少要给k个朋友打电话

{% raw %}




{% endraw %}

5
1 2 2
1 3 2
1 4 2
1 5 2

{% raw %}





{% endraw %}

题解

根据题意画出图像,可以非常容易发现最终形成一棵以西瓜为树根的树
朋友会一路清扫倒西瓜所在的房间,因此只有住在"树叶"的朋友有可能清扫

根据这个思路来分析每一个节点
可以发现:

  1. 如果从一个节点的子节点已经有 a 个朋友清扫,那么从该节点到树根都不需要再找朋友清扫
  2. 如果该节点的所有子节点都没有朋友清扫,那么如果从该节点到树根有需要清扫的路,只需要找一个朋友清扫即可

因此可以发现,对于每一个节点,从树叶到该节点所需的最少朋友数只与其子节点有关,符合 动态规划 的特点,属于 树形dp

dp[i] 表示从叶子到第 i 个节点的所需要最少的朋友数, dp[1] 即为答案
dp[i] = sum{ max(dp[j],Need_Clean) } 其中 ji 的所有子节点, Need_Clean 为道路 (i,j) 是否需要清扫

只需要一个 DFS 即可解决

代码

```cpp 西瓜理发记(三) https://github.com/OhYee/sourcecode/tree/master/ACM 代码备份 #include

#include #include #include using namespace std;

const int maxn = 1e5+5;

struct path{
int u,v;
bool k;
path(int a,int b,int c):u(a),v(b),k(c){}
};
struct Node{
list children;
int father;
};

Node node[maxn];

int dfs(int t){
int ans=0;
for(list::iterator it=node[t].children.begin();it!=node[t].children.end();it++){
int tt = it->v;
if(tt == node[t].father)
continue;
node[tt].father = t;
ans += max(dfs(tt),(int)it->k);
}
return ans;
}

int main(){
cin.tie(0);
cin.sync_with_stdio(false);

int n;
while(cin >> n){
    for(int i=1;i<=n;i++){
        node[i].father=-1;
        node[i].children.clear();
    }
         
    int a,b,c;
    for(int i=1;i<n;i++){
        cin>>a>>b>>c;
        node[a].children.push_back(path(a,b,c-1));
        node[b].children.push_back(path(b,a,c-1));
    }   
    cout << dfs(1) << endl;
}

}

</div>