POJ - 4045 Power Station 樹形dp
阿新 • • 發佈:2019-01-01
題目連結:點選檢視
題意:n個城市節點構成的一棵樹,節點i到節點j的電量損耗為 I*I*R*(i到j的路徑所含邊數),現在要在某個結點上修建一個供電站,使得這個結點到所有其它節點的總損耗量最小。
題解:I*I*R可以提出來,剩下的就求,選擇一個點,求其他點到這個點的距離和最小就可以了,樹形dp,先求一個節點,記錄每個節點子代的個數,逐步向下求即可
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; typedef long long ll; const int N=50010; ll dp[N],son[N]; int n; ll I,R; vector<int> v[N]; void dfs1(int u,int fa) { dp[u]=0; son[u]=1; for(int i=0;i<v[u].size();i++) { int to=v[u][i]; if(to==fa) continue; dfs1(to,u); dp[u]+=dp[to]+son[to]; son[u]+=son[to]; } } ll minn; int ans[N],len; void dfs2(int u,int fa) { minn=min(minn,dp[u]); for(int i=0;i<v[u].size();i++) { int to=v[u][i]; if(to==fa) continue; dp[to]=dp[u]-son[to]+(n-son[to]);// 子代的孩子數就不走這條邊了,剩下的節點要走這條邊 dfs2(to,u); } } void dfs3(int u,int fa) { if(minn==dp[u]) { ans[++len]=u; } for(int i=0;i<v[u].size();i++) { int to=v[u][i]; if(to==fa) continue; dfs3(to,u); } } int main() { int T; int x,y; scanf("%d",&T); while(T--) { scanf("%d%lld%lld",&n,&I,&R); for(int i=1;i<=n;i++)v[i].clear(); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); v[x].push_back(y); v[y].push_back(x); } minn=1e18,len=0; dfs1(1,0); // 先求節點1 dfs2(1,0); // 求子代 和 最小值 dfs3(1,0); // 求 有多少最小值 sort(ans+1,ans+1+len); printf("%lld\n",I*I*R*minn); for(int i=1;i<=len;i++) printf("%d%c",ans[i]," \n"[i==len]); printf("\n"); } return 0; }