BZOJ 1912 [Apio2010]patrol 巡逻
来源:互联网 发布:在淘宝上买摩托车 编辑:程序博客网 时间:2024/05/17 00:51
一眼看出了是求树的直径,然而没学过可怎么破。。。
然后百度自学了一波
http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html
大概方法就是任找一个点,找离他最远的点,此点必为直径的端点,然后以此为基准再找一个离他最远的点,连成的链即树的直径。(证明见上地址)
k=0,观察到每条边必走两遍,无关于出发点
k=1即一个裸的树的直径,原因是图中每个边都至少要走两次,加一条路可以少走一遍,而多加这条路的cost(1),设直径为len1,那么ans1=2(n-1)-len1+1
k=2,则在k=1的基础上考虑。再求一条次长链len2,最长链与次长链相交,那么若直接ans1-len2+1必然是错的。因为通过新建路,本来需要往返的边可以省去一次回去的花费,而一段链被跳过两次,则意味着根本没有被遍历到,于是每条边需要再加上两遍,减两遍加两遍,二者相抵,即第二次需要将两次相重的再加回来。而不能先计算再加,因为有可能加的值(即相重的边)会很大,于是先进行等效的-1操作,将第一次选的链上所有边权改为-1,再找次长链。
而这里有一个问题,即上方给出的树的直径寻法针对的是正权(证明的条件是加边则必然权会更大),而负权就会很尴尬了。。。
其实搞一个树形DP就好了,每个节点记一个最长链和次长链,二者通过lca相连,每次记录一下,DP完以后ans2=2(n-1)-len1+1-len2+1即可
#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<algorithm>using namespace std;const int maxn=100005;struct edge{ int to,next,val;}e[maxn<<1];int cnt=1,n,k,maxi,key,xx,yy;int head[maxn],son1[maxn],son2[maxn];void insert(int a,int b){ e[++cnt].to=b;e[cnt].val=1;e[cnt].next=head[a];head[a]=cnt;}int dfs(int x,int fa){ int max1,max2; max1=max2=0;//自己到自己起码有一条0的路 son1[x]=son2[x]=x; for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa) { int now=e[i].val+dfs(e[i].to,x); if(now>max1) { max2=max1; max1=now; son2[x]=son1[x]; son1[x]=son1[e[i].to]; } else if(now>max2) { max2=now; son2[x]=son1[e[i].to]; } } if(max1+max2>maxi) { maxi=max1+max2; xx=son1[x]; yy=son2[x]; } return max1;}void color(int x,int fa,int fin){ static bool flag=true; for(int i=head[x];i&&flag;i=e[i].next)if(e[i].to!=fa) { e[i].val=e[i^1].val=-1; if(e[i].to==fin)flag=false; if(!flag)return; color(e[i].to,x,fin); if(!flag)return; e[i].val=e[i^1].val=1; }}int main(){ scanf("%d%d",&n,&k); for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v), insert(u,v), insert(v,u); maxi=0; dfs(1,-1);int len1=maxi; if(k==1){printf("%d",2*(n-1)-len1+1);return 0;} color(xx,-1,yy); maxi=0; dfs(1,-1);int len2=maxi; printf("%d",2*(n-1)-len1+1-len2+1); return 0;}
k=1的情况:树的直径求法
#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<algorithm>using namespace std;const int maxn=100005;struct edge{ int to,next,val;}e[maxn<<1];int cnt=1,n,k,maxi,key,xx,yy;int head[maxn],dist[maxn];void insert(int a,int b){ e[++cnt].to=b;e[cnt].val=1;e[cnt].next=head[a];head[a]=cnt;}void dfs(int x,int fa){ for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa) { dist[e[i].to]=dist[x]+e[i].val; if(dist[e[i].to]>maxi)key=e[i].to,maxi=dist[e[i].to]; dfs(e[i].to,x); }}int length(){ maxi=-0x3f3f3f3f; memset(dist,0,sizeof dist); dfs(1,-1); memset(dist,0,sizeof dist); xx=key; maxi=-0x3f3f3f3f; dfs(key,-1); yy=key;}int main(){ scanf("%d%d",&n,&k); for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v), insert(u,v), insert(v,u); length();int len1=maxi; printf("%d",2*(n-1)-len1+1-len2+1);}
阅读全文
0 0
- 【BZOJ 1912】 [Apio2010]patrol 巡逻
- bzoj 1912: [Apio2010]patrol 巡逻
- BZOJ 1912 [Apio2010]patrol 巡逻
- BZOJ 1912 [Apio2010]patrol 巡逻
- bzoj 1912 [Apio2010]patrol 巡逻 树形dp
- 1912: [Apio2010]patrol 巡逻
- 1912: [Apio2010]patrol 巡逻
- [BZOJ 1912][Apio2010]patrol 巡逻:树的直径
- [Apio2010]patrol 巡逻
- BZOJ1912[Apio2010]patrol 巡逻
- 【bzoj1912】[Apio2010]patrol 巡逻
- bzoj1912: [Apio2010]patrol 巡逻
- bzoj1912 [Apio2010]patrol 巡逻
- 【bzoj1912】[Apio2010] patrol 巡逻 树形dp
- [bzoj1912][Apio2010]patrol 巡逻(树上dp)
- [BZOJ 1912][APIO 2010]patrol 巡逻(树的直径)
- [BZOJ1912][Apio2010]patrol 巡逻(树上最长链)
- 【bzoj1912】[Apio2010]patrol 巡逻(树上最长链)
- div元素及其属性布局页面
- R记录程序运行时间
- 语音识别的技术路线学习笔记
- Course Schedule解题心得
- java架构师大型分布式项目实战视频教程
- BZOJ 1912 [Apio2010]patrol 巡逻
- ActiveMQ实践
- Python--day7 练习题1
- L22 yum更换国内源,yum下载rpm包,源码包安装
- thinkphp(3) 字符串截取函数msubstr
- 303. Range Sum Query
- java架构师大型分布式项目实战视频教程
- Ubuntu Server 16.04 安装MySQL并设置远程访问
- Python更快的解析JSON大文件