poj 4045 Power Station(初涉樹形dp)
http://poj.org/problem?id=4045
大致題意:有n個村莊,求將發電站建在哪一個村莊使得花費最少。這是一個無向無環圖。簡化一下就是求一個節點使它到其他所有節點的距離和最小。
起初一直在向最短路上靠,但因為節點和邊數太大,必定TLE。然後無比強大的嘯神隨便寫了兩個dfs就過掉了,簡直膜拜。賽後搜了搜題解,發現這是道樹形dp。sad,真的要好好刷dp了。
大體思路是將這個無向無環圖看做一個樹,我們就在這個樹上進行動態規劃。首先先隨便拿一個節點看做根節點(假設節點1),計算出它到其他點的最小距離和,那麼接下來當它的兒子做根節點的時候,根據父親節點的值以及他們的關係就可以直接計算齣兒子節點做根節點的距離和,具體是除該節點及其子樹之外的所有節點的距離都加1,而該節點及其子節點距離都減1。這個距離是隨便拿一個根節點dfs計算出來的。
設dp【】表示每個節點做根節點時它到子節點的距離之和,真正用到的是dp[1],son【】表示每個節點的孩子節點數目,包括自身。若已知父親節點的花費cost[pre],那麼當前節點u的花費cost[u] = cost[pre] + n-son[u] -son[u]。
總之,兩次dfs,第一次為了求得dp[1]和每個節點的孩子數目son[],第二次是有父親節點的花費求得當前節點的花費。
#include <stdio.h>#include <iostream>#include <map>#include <stack>#include <vector>#include <math.h>#include <string.h>#include <queue>#include <string>#include <stdlib.h>#include <algorithm>#define LL long long#define _LL __int64#define eps 1e-8#define PI acos(-1.0)using namespace std;const int maxn = 50000+10;struct node{int u,v,next;}edge[maxn*2];int cnt,head[maxn];int n,I,R;int son[maxn];//每個節點的兒子節點數目,這裡包含該節點本身方便計算。LL dp[maxn];//每個根節點的子節點到該節點的距離和LL cost[maxn];//以每個節點為根的花費void init(){cnt = 0;memset(head,-1,sizeof(head));}void add(int u, int v){edge[cnt] = (struct node){u,v,head[u]};head[u] = cnt++;}void dfs(int u, int pre){dp[u] = 0;son[u] = 1;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;if(v == pre) continue;dfs(v,u);son[u] += son[v]; //兒子數目dp[u] += dp[v] + son[v];//u到u的各個子節點的距離之和。}}void cal(int u, int pre){ if(u != 1) cost[u] = cost[pre]+n-son[u]-son[u]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if(v == pre) continue; cal(v,u); }}int main(){int test;scanf("%d",&test);while(test--){scanf("%d %d %d",&n,&I,&R);int u,v;init();for(int i = 0; i < n-1; i++){scanf("%d %d",&u,&v);add(u,v);add(v,u);}//假設1為根節點dfs(1,0); memset(cost, 0, sizeof(cost)); cost[1] = dp[1]; cal(1,0); LL Min = cost[1]; for(LL i = 2; i <= n; i++) Min = min(Min,cost[i]); cout << Min*I*I*R << endl; bool flag = false; for(LL i = 1; i <= n; i++) { if(cost[i] == Min) { if(flag == false) { flag = true; cout << i; } else cout << " " << i; } } cout << endl << endl;}return 0;}