题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)
本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打。。。一打打到第二天QAQ
首先什么边也不加时,总路程就是2*(n-1)
考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n-直径-1,如果能加一条边的话,因为希望减少的尽可能多,那么只需要把直径的首尾接起来,就不需要来回走,加一就是加了这一条新加入的边。
而k=2的时候,首先还是往最长链上面思考。然而做k=1的时候已经用掉了一段,我们需要k=2的和k=1的不重叠。
于是乎,我们跑完直径后之后把直径上的边权全部修改为-1,再跑一遍直径就可以了。那权值为-1的边又被选了就是考虑第一次算这条边的时候加了1,第二次的时候是-1,相当于是这条边没有产生任何贡献。所以最后答案是2(n-1)-(直径1-1)-(直径2-1)=2n-直径1-直径2
哪位大佬能教教我DP记路径吗。。。。感激不尽( ⊙ o ⊙ )啊!
我的傻乎乎的代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define R register int
using namespace std;
const int N=,Inf=0x3f3f3f3f;
inline int g() {
R ret=,fix=; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-:fix;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret*fix;
}
int n,k,mx,mx1,cnt,st,ed;
int pre[N],fir[N],cnte[N],d[N];
struct edge{
int v,w,nxt;
#define v(i) e[i].v
#define w(i) e[i].w
#define nxt(i) e[i].nxt
}e[N<<];
inline void add(int u,int v,int w) {v(++cnt)=v,w(cnt)=w,nxt(cnt)=fir[u],fir[u]=cnt;}
namespace _dp {
void dp(int u,int fa) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
dp(v,u);
mx=max(mx,d[u]+d[v]+w(i));
d[u]=max(d[u],d[v]+w(i));
}
}
inline void solve() {
memset(d,,sizeof(d));
dp(,);
}
}
inline void dfs(int u,int fa) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
d[v]=d[u]+w(i);
dfs(v,u);
}
}
inline void solve() {
memset(d,0x3f,sizeof(d));
d[]=; dfs(,); mx=-Inf; st=,ed=;
for(R i=;i<=n;++i) if(d[i]>mx&&d[i]!=Inf&&i!=)
mx=d[i],st=i;
memset(d,0x3f,sizeof(d));
d[st]=,dfs(st,); mx=-Inf;
for(R i=;i<=n;++i) if(d[i]>mx&&d[i]!=Inf&&i!=st)
mx=d[i],ed=i;
}
inline void fd_p(int u,int fa) {
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
fd_p(v,u);
pre[v]=u;
cnte[v]=i;
}
}
signed main() {
n=g(),k=g();
for(R i=,u,v;i<n;++i) u=g(),v=g(),add(u,v,),add(v,u,);
solve();
if(k==) {printf("%d\n",*n-mx-); return ;}
fd_p(st,); mx1=mx; pre[st]=;
for(R i=ed;i;i=pre[i]) if(cnte[i]&) w(cnte[i])=-,w(cnte[i]+)=-; else w(cnte[i])=-,w(cnte[i]-)=-;
mx=;
_dp::solve();
printf("%d\n",*n-mx1-mx);
}
我看不懂的代码(fromljh2000%%%%%)
#include<cstdio>
#include<iostream>
#include<cstring>
#define R register int
using namespace std;
const int N=;
inline int g() {
R ret=,fix=; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-:fix;
do ret=ret*+(ch^); while(isdigit(ch=getchar())); return ret*fix;
}
int n,k,cnt,anss,ans,rt,S,SP;
int fir[N],nxt[N],nxte[N],f[N][];
struct edge{
int v,w,nxt;
#define v(i) e[i].v
#define w(i) e[i].w
#define nxt(i) e[i].nxt
}e[N<<];
inline void add(int u,int v,int w) {v(++cnt)=v,w(cnt)=w,nxt(cnt)=fir[u],fir[u]=cnt;}
inline void dfs(int u,int fa) {
R crt,s=,sp=;
for(R i=fir[u];i;i=nxt(i)) {
R v=v(i);
if(v==fa) continue;
dfs(v,u);
crt=f[v][]+w(i);
if(crt>f[u][]) s=nxt[u],sp=nxte[u],f[u][]=f[u][],f[u][]=crt,nxt[u]=v,nxte[u]=i;
else if(crt>f[u][]) f[u][]=crt,s=v,sp=i;
}
if(f[u][]+f[u][]>ans) {
ans=f[u][]+f[u][]; rt=u,S=s,SP=sp;
}
}
signed main() {
n=g(),k=g(); R x;
for(R i=,u,v;i<n;++i) u=g(),v=g(),add(u,v,),add(v,u,);
dfs(,);
anss=*(n-)-ans+;
if(k==) {printf("%d\n",anss); return ;}
if(f[rt][]>) {
x=S; w(SP)=-;
while(nxt[x]) w(nxte[x])=-,x=nxt[x];
}
x=rt;
while(nxt[x]) w(nxte[x])=-,x=nxt[x];
ans=; memset(f,,sizeof(f));
dfs(,); anss-=ans-; printf("%d\n",anss);
}
2019.04.02
题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)的更多相关文章
- 树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925
题目传送门 我们先来介绍一个概念:树的直径. 树的直径:树中最远的两个节点间的距离.(树的最长链)树的直径有两种方法,都是$O(N)$. 第一种:两遍bfs/dfs(这里写的是两遍bfs) 从任意一个 ...
- 洛谷 P3629 [APIO2010]巡逻 解题报告
P3629 [APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通 ...
- 洛谷P3629 [APIO2010]巡逻(树的直径)
如果考虑不算上新修的道路,那么答案显然为\(2*(n-1)\). 考虑\(k=1\)的情况,会发现如果我们新修建一个道路,那么就会有一段路程少走一遍.这时选择连接树的直径的两个端点显然是最优的. 难就 ...
- [洛谷P3629] [APIO2010]巡逻
洛谷题目链接:[APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以 ...
- P3629 [APIO2010]巡逻
题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄.每条道 ...
- 洛谷 P3629 [APIO2010]巡逻
题目在这里 这是一个紫题,当然很难. 我们往简单的想,不建立新的道路时,从1号节点出发,把整棵树上的每条边遍历至少一次,再回到1号节点,会恰好经过每条边两次,路线总长度为$2(n-1)$,根据树的深度 ...
- luogu题解 P1099 【树网的核】树的直径变式+数据结构维护
题目链接: https://www.luogu.org/problemnew/show/P1099 https://www.lydsy.com/JudgeOnline/problem.php?id=1 ...
- Luogu 3629 [APIO2010]巡逻
先考虑$k = 1$的情况,很明显每一条边都要被走两遍,而连成一个环之后,环上的每一条边都只要走一遍即可,所以我们使这个环的长度尽可能大,那么一棵树中最长的路径就是树的直径. 设直径的长度为$L$,答 ...
- 【BZOJ-1912】patrol巡逻 树的直径 + DFS(树形DP)
1912: [Apio2010]patrol 巡逻 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1034 Solved: 562[Submit][St ...
随机推荐
- XML文件的特点
1.这个东西的规则比较简单,并且人眼看起来也比较容易理解,结构上也比较好操作,并且并无与任何编程语言绑定. 所以,很多编程语言就都为XML这个东西编写了读写XML的库,所以XML看起来所谓的通用,其实 ...
- legend2---开发日志15(功能需求明确,设计好类和结构的好处是)
legend2---开发日志15(功能需求明确,设计好类和结构的好处是) 一.总结 一句话总结: 极快简化编程,节约大量时间 1.多个类型的物品,比如商店和寻宝的丹药,装备,特性书,英雄石等等 应该怎 ...
- HDU 2035 人见人爱A^B(二分求幂,快速求幂)
题意:求A的B次方的后三位数字 思路1:常规求幂,直接取余求解 代码: #include<iostream> #include<cstdio> using namespace ...
- HDU 6170 Two strings (dp)
/** * 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6170 * 字符串match, '.'代表匹配任意一个字符,"*" 代表 ...
- 1087 All Roads Lead to Rome (30)(30 分)
Indeed there are many different tourist routes from our city to Rome. You are supposed to find your ...
- ACM学习历程——HDU3333 Turing Tree(线段树 && 离线操作)
Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems abou ...
- 1068 Bash游戏 V3
1068 Bash游戏 V3 题目来源: Ural 1180 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 有一堆石子共有N个.A B两个人轮流拿 ...
- 【Lintcode】136.Palindrome Partitioning
题目: Given a string s, partition s such that every substring of the partition is a palindrome. Return ...
- SimpliciTI简介
SimpliciTI简介 SimpliciTI是TI开发的一份专门针对其CCxxxx系列无线通信芯片的网络协议.按照其官方说法SimpliciTI是一个基于连接的点对点通讯协议.它支持两种网络拓扑结构 ...
- Redis的Spring配置讲解
Redis是一种特殊类型的数据库,他被称之为key-value存储 本文覆盖缓存和存储两方面进行说明,使用的是Spring 4.0和Java配置方式 代码地址下载地址:https://github.c ...