-
F - Warm up
- HDU - 4612
- 定义:
- 一棵树的直径就是这棵树上存在的最长路径。
- 求法:
- 两次dfs或bfs。第一次任意选一个点进行dfs(bfs)找到离它最远的点,此点就是最长路的一个端点,再以此点进行dfs(bfs),找到离它最远的点,此点就是最长路的另一个端点,于是就找到了树的直径。
- 证明:
- 假设此树的最长路径是从s到t,我们选择的点为u。反证法:假设搜到的点是v。
- 1、v在这条最长路径上,那么dis[u,v]>dis[u,v]+dis[v,s],显然矛盾。
- 2、v不在这条最长路径上,我们在最长路径上选择一个点为po,则dis[u,v]>dis[u,po]+dis[po,t],那么有dis[s,v]=dis[s,po]+dis[po,u]+dis[u,v]>dis[s,po]+dis[po,t]=dis[s,t],即dis[s,v]>dis[s,t],矛盾。
- 树DP,思路很简单,树的直径必然是树上某一个点开始往下的最长链和次长链之和。而实现的时候只要保留最大值的大小就可以了,比较简单不讲了看代码就好。
-
#include<bits/stdc++.h> using namespace std; #define LL long long const int INF=0x3f3f3f3f; const int N=200010; const int M=1000010; struct Edge { int v,nt,flag; } edge[M<<2]; int s[N],cnt; int n,m; int dfn[N],low[N],dep,vis[N]; int id[N],res; bool instack[N]; int nbridge,bridge[M][2]; int maxlen; stack<int>st; void AddEdge(int u,int v) { edge[cnt].v=v; edge[cnt].nt=s[u]; edge[cnt].flag=1; s[u]=cnt++; edge[cnt].v=u; edge[cnt].nt=s[v]; edge[cnt].flag=1; s[v]=cnt++; } void tarjan(int u) { dfn[u]=low[u]=++dep; st.push(u); instack[u]=1; for(int i=s[u]; i!=-1; i=edge[i].nt) { int v=edge[i].v; if(edge[i].flag==0)continue; edge[i].flag=edge[i^1].flag=0; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) { bridge[nbridge][0]=u; bridge[nbridge++][1]=v; } } else if(instack[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { int temp; do { id[temp=st.top()]=res; st.pop(); instack[temp]=0; } while(temp!=u); res++; } } int dfs(int u,int pre) { int temp=0; for(int i=s[u]; i!=-1; i=edge[i].nt) { int v=edge[i].v; if(v==pre)continue; int d=dfs(v,u); maxlen=max(maxlen,temp+d); temp=max(temp,d); } return temp+1; } int main() { while(~scanf("%d%d",&n,&m)&&(n+m)) { memset(s,-1,sizeof s); cnt=0; for(int i=0; i<m; i++) { int u,v; scanf("%d%d",&u,&v); AddEdge(u,v); } memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(instack,0,sizeof instack); nbridge=0,res=0,dep=0; while(!st.empty()) st.pop(); for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i); memset(s,-1,sizeof s); cnt=0; for(int i=0; i<nbridge; i++) { int u=id[bridge[i][0]],v=id[bridge[i][1]]; AddEdge(u,v); } maxlen=0; dfs(0,-1); printf("%d\n",nbridge-maxlen); } return 0; }
F - Warm up HDU - 缩点dp求树直径
最新推荐文章于 2019-08-05 09:34:05 发布