HDU--3721[Building Roads] 枚举+求最长路O(N^2)
来源:互联网 发布:母鸡模具淘宝交易 编辑:程序博客网 时间:2024/06/01 08:54
题意:
给一棵树,可以移动树上的一条边,但是必须保证移动之后的图还是一棵树,问如何移动才能使得移动之后的树的直径最短。
(1):分别求出两个子树的直径du和dv.
(2):在每棵子树中求一点x。使这点到子树中的其他任意一点的最长距离最短。由分析可知,这一点x一定在子树的直径上,且在直径的中心两点中的其中一点(证明如下)。
(3):分别求出两棵子树的那两个关键点x后。更新答案ans_l=min(ans_l,max(du,dv,ss+ee+w)). //ss,ee是两棵子树的关键点x到其他点的最长距离;w是当前枚举边的长度
证明如下: 摘自http://hi.baidu.com/dispossessed/blog/item/660a8a294b9d62459922ed5f.html
给一棵树,可以移动树上的一条边,但是必须保证移动之后的图还是一棵树,问如何移动才能使得移动之后的树的直径最短。
思路:
(1):分别求出两个子树的直径du和dv.
(2):在每棵子树中求一点x。使这点到子树中的其他任意一点的最长距离最短。由分析可知,这一点x一定在子树的直径上,且在直径的中心两点中的其中一点(证明如下)。
(3):分别求出两棵子树的那两个关键点x后。更新答案ans_l=min(ans_l,max(du,dv,ss+ee+w)). //ss,ee是两棵子树的关键点x到其他点的最长距离;w是当前枚举边的长度
证明如下: 摘自http://hi.baidu.com/dispossessed/blog/item/660a8a294b9d62459922ed5f.html
假设要求的点不是直径上面的点,那么由于原图是一棵树,取这个点到直径的最短路径,交直径与一个点,这个点到其他点的最长距离一定大于交点到其他点的最长距离,这样
就说明了要求的点一定是直径上面的点,既然是直径上面的点,因为直径是一条链,显然它一定是中心附近的点。
PS.一开始的复杂度是O(N^3),TLE,后然看了别人的题解后发现“关键点”只可能在直径的中心附近的两个点中的一个。这样就把复杂度降到了O(N^2).
CODE:
/*枚举+求最长路O(N^2)*//*AC代码:170ms*/#include <iostream>#include <cstdio>#include <memory.h>#include <algorithm>#include <queue>#define MAXN 2505#define INF 1e8#define min(a,b) (a<b?a:b)#define max(a,b) (a>b?a:b)using namespace std;struct edge{ int u,v,w,next; bool ok;}E[3*MAXN];int head[MAXN];int ecnt;int dis[MAXN],road[MAXN],pre[MAXN],cnt;bool vis[MAXN],col[MAXN];int N,ans_l,cas,lenc;queue<int>Q;void Insert(int u,int v,int w){ E[ecnt].u=u; E[ecnt].v=v; E[ecnt].w=w; E[ecnt].ok=true; E[ecnt].next=head[u]; head[u]=ecnt++;}void Print(){ int i; for(i=1;i<=N;i++) printf("%d ",col[i]); printf("**\n");}void Init(){ int i,u,v,w; memset(head,-1,sizeof(head));ecnt=0; scanf("%d",&N); for(i=1;i<N;i++) { scanf("%d%d%d",&u,&v,&w); u++;v++; Insert(u,v,w); Insert(v,u,w); }}int BFS(int s){ int i,u,v,w,res; while(!Q.empty()) Q.pop(); memset(vis,false,sizeof(vis)); memset(dis,-1,sizeof(dis)); memset(pre,-1,sizeof(pre)); vis[s]=true; dis[s]=0; Q.push(s); while(!Q.empty()) { u=Q.front();Q.pop(); for(i=head[u];i!=-1;i=E[i].next) { if(E[i].ok==false) continue; v=E[i].v;w=E[i].w; if(!vis[v]) { dis[v]=dis[u]+w; pre[v]=i; vis[v]=true; Q.push(v); } } }res=0;for(i=1;i<=N;i++){if(dis[i]==-1) continue;if(dis[i]>res) res=dis[i];}return res;}int Go(int x,bool flag){ int i,u,v,s,e,Max,l,temp[MAXN],tcnt; BFS(x); s=0;Max=0;lenc=INF; for(i=1;i<=N;i++)//染色 { if(vis[i]) { col[i]=flag; if(dis[i]>Max) {s=i;Max=dis[i];} } } BFS(s); e=0;Max=0; for(i=1;i<=N;i++) { if(vis[i]) { if(dis[i]>Max) {e=i;Max=dis[i];} } }int sum=0;tcnt=0; u=e; while(true) { l=pre[u]; if(l==-1) break; temp[tcnt++]=l;sum+=E[l].w; u=E[l].u; }sum/=2;int len=0;for(i=0;i<tcnt;i++){len+=E[temp[i]].w;if(len>sum) break;}//最好的点就在这两个点之间if(tcnt==0)//避免RE{lenc=0;return Max;}u=E[temp[i]].u;v=E[temp[i]].v;int lu=BFS(u);int lv=BFS(v);//printf("&%d %d %d %d %d\n",tcnt,u,v,lu,lv);lenc=min(lu,lv); return Max;}void fuck(int ith){ int i,u,v,s,e,ss,ee,ds,de,dw,Max; memset(col,false,sizeof(col)); //printf("%d %d \n",road[ith],road[ith]^1); E[road[ith]].ok=E[road[ith]^1].ok=false; s=E[road[ith]].u; e=E[road[ith]].v; ds=Go(s,1); ss=lenc; de=Go(e,0); ee=lenc; //Print(); dw=ss+ee+E[road[ith]].w; int res=max(dw,max(ds,de)); //printf("*%d %d %d %d %d %d\n",s,e,ans_l,ds,de,dw); ans_l=min(ans_l,res); E[road[ith]].ok=E[road[ith]^1].ok=true;}void Run(){ int i,s,e,u,Max,l; BFS(1); s=1;Max=dis[1]; for(i=2;i<=N;i++) { if(dis[i]>Max) {s=i;Max=dis[i];} } BFS(s); e=1;Max=dis[1]; for(i=2;i<=N;i++) { if(dis[i]>Max) {e=i;Max=dis[i];} } ans_l=Max; cnt=0; u=e; while(true) { l=pre[u]; if(l==-1) break; road[cnt++]=l; u=E[l].u; } for(i=0;i<cnt;i++) { fuck(i); }}void Solve(){ int i; Run();//求出最长路径 printf("Case %d: %d\n",cas++,ans_l);}int main(){ int T; cas=1; scanf("%d",&T); while(T--) { Init(); Solve(); }return 0;}
- HDU--3721[Building Roads] 枚举+求最长路O(N^2)
- HDU 3721 Building Roads
- HDU 3721 Building Roads
- HDU 3721 Building Roads 树形dp + 枚举直径
- HDU 3068 最长回文(manacher O(n)求回文算法)
- HDU--4007[Dave] O(N^2)枚举
- HDU 1025 Constructing Roads (最长上升子序列O(n*logn)算法)
- O(n^3)、O(n^2)和O(n)求最长回文子串
- HDU 3068-最长回文(Manacher算法O(n)求最长回文串)
- hdu 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列的o(nlog(n))算法)
- hdu 3721 uvalive 5026 building roads
- 【树形DP】 HDU 3721 Building Roads
- 树形dp-hdu-3721-Building Roads
- hdu 3721 Building Roads 树的直径
- O(n) 求 最长回文子串
- O(n) 求 最长回文子串
- O(n)求最长回文子串
- O(n)求最长回文字串
- 无法对数据库'XXX' 执行删除,因为它正用于复制"的解决方
- JVM学习总结(转载)
- 做一个决定
- apache与tomcat整合
- POJ 2886 Who Gets the Most Candies?
- HDU--3721[Building Roads] 枚举+求最长路O(N^2)
- java中判断字符串是否相同不能用==
- 测试分类及说明
- hdu 2149【巴什博奕】
- java缓存
- C#去除HTML标签方法
- 赌博中,关于保赢时赔率的小问题、、、
- 一些疑惑
- linux打包环境升级命令