標籤:
膜拜了NN個大神的代碼,看了一整天,弱菜傷不起啊。求拜師啊
問題分析:求樹上每個節點到其它節點的最遠距離
每個節點到其它節點的最遠距離就是以該節點為根的樹所能達到的最大深度,這樣子的話,要把每個節點轉化為根,總共dfs的次數為節點數,肯定逾時
於是~
一個節點的最長路:1.從該節點往下取得最長路(子樹部分) 2.從該節點往上取得的最長路(父節點往上的部分)
情況1:自下而上的dfs(先深搜後操作)
情況2:自上而下的dfs(先操作後深搜){
如果節點u的子節點v在 以u為父親的子樹上的最長路,那麼點v的最長路由u的父親路和次長路中的max取得
否則 點v的最長路由u的父親路和最長路中的max取得
}
(畫顆樹就可以非常清楚了)
貼上自己的代碼~~~
^。^
<span style="font-size:18px;">/*dp[i][0] 表示以i為父親的子樹中的最大距離dp[i][1] 表示以i為父親的子樹中的次大距離dp[i][2] 表示i的父樹的最大距離*/#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#define ms(s,i) memset(s,i,sizeof s)#define ffl(i,r) for(int i=head[r];i!=-1;i=edge[i].next)#define lng long long#define pb push_back#define linf 100000#define M 11000#define fx(i,x,n) for(int i=x;i<n;++i)using namespace std;int dp[M][3],f[M],l[M],vis[M];template<class T> T gcd(T a,T b){return b==0?a:gcd(b,a%b);}template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}struct pp{int v,w,next;}edge[M*2];int tot,head[M],root,n,m;inline void addedge(int u,int v,int w,int *h){edge[tot].v=v,edge[tot].w=w,edge[tot].next=h[u],h[u]=tot++;}//鄰接表void dfs1(int u)//自下而上,更新子樹的最長路和次長路,先dfs後操作{ vis[u]=1; ffl(i,u){//引用鄰接表 int v=edge[i].v;//節點u的子節點 if(vis[v]) continue; dfs1(v); if(dp[u][0]<dp[v][0]+edge[i].w){//最長的是所有子節點中的max dp[u][1]=dp[u][0]; dp[u][0]=dp[v][0]+edge[i].w; } else if(dp[u][1]<dp[v][0]+edge[i].w){//次長的是所有子節點的second dp[u][1]=dp[v][0]+edge[i].w; } }}void dfs2(int u){ vis[u]=1; ffl(i,u){//引用鄰接表 int v=edge[i].v;//節點u的子節點 if(vis[v]) continue; if(dp[v][0]+edge[i].w==dp[u][0]){//節點v的最長路+邊(u,v)的權值=節點u的最長路,那麼節點v在節點u的最長路上 dp[v][2]=max(dp[u][1],dp[u][2])+edge[i].w;//等於父親路和次長路中的MAX } else dp[v][2]=max(dp[u][2],dp[u][0])+edge[i].w;//否則等於父親路和最長路中的MAX dfs2(v);//自上而下 }}int main(){ while(scanf("%d",&n)!=EOF){ int u,w; tot=0,ms(head,-1);//記得初始化 for(int i=2;i<=n;++i){ scanf("%d%d",&u,&w); addedge(u,i,w,head);addedge(i,u,w,head);//鄰接表構建無向圖 } ms(vis,0),ms(dp,0); dfs1(1); ms(vis,0);//重新初始化vis dfs2(1); for(int i=1;i<=n;++i){ printf("%d\n",max(dp[i][0],dp[i][2]));//最長路和父親路中的MAX } } return 0;}</span>
HDU 2196——Computer(樹形DP)