P8028 [COCI2021-2022#3] Cijanobakterije
简要题意
给定一个森林,可以在树与树之间连边,不可成环,求最长链。
解析
对于一棵树而言,她本身的最长链自然就是她的直径。
贪心的想,把所有的树的直径全部连接起来就是最长的那一条链。
所以,对于每一棵树求出她的直径然后求和就好了。
特别注意,这题的长度是指节点的个数,因此比边数大
代码实现
树的直径有两种求法:两遍搜索和树形 DP。
前者可以保存遍历路径但无法处理负边权,后者则正好反之。
搜索
先选树上任意一点
理论上 DFS 与 BFS 均可,但写 DFS 的似乎更多。
DP
别的题解讲的还挺明白的,而且本题也没有负边权我不会,这里就不放了。
此外,树的直径还有不少性质,这里贴个链接,如需自取。
终于来到了喜闻乐见的代码环节。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+12;
int n,m;
int head[maxn],cnt=0;
struct node {
int nxt,to;
} edge[maxn];
bool vis[maxn],vis2[maxn];
int ans=0,o=0,dis=0;
void add(int u,int v) {
cnt++;
edge[cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs1(int u,int d) {
vis[u]=1;
if(d+1>dis) {
dis=d+1;
o=u;
}
for(int i=head[u]; i; i=edge[i].nxt) {
int v=edge[i].to;
if(!vis[v])
dfs1(v,d+1);
}
}
void dfs2(int u,int d) {//可以跟dfs1和到一起的,不过容易出锅,模拟赛100->30。
vis2[u]=1;
dis=max(dis,d+1);
for(int i=head[u]; i; i=edge[i].nxt) {
int v=edge[i].to;
if(!vis2[v]) {
dfs2(v,d+1);
}
}
}
int main() {
cin>>n>>m;
for(int i=1; i<=m; i++) {
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=1; i<=n; i++) {
if(!vis[i]) {
dis=0;//记得清零
dfs1(i,0);
dfs2(o,0);
ans+=dis;
}
}
cout<<ans<<endl;
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】