 /**//*
題意:一棵樹上,每個(gè)節(jié)點(diǎn)有cnt[i]個(gè)人 每條邊有權(quán)值
現(xiàn)要求一個(gè)點(diǎn),使得其他點(diǎn)到該點(diǎn)的所有代價(jià)最小
代價(jià)即 ∑人數(shù)*經(jīng)過邊的權(quán)值

tree dp 自底向上 自頂向下更新2次即可

先dfs1求得:
ans[u] 以u為根的子樹,所有點(diǎn)到u的代價(jià)
sum[u] u及其子樹所有節(jié)點(diǎn)的人數(shù)
同時(shí)記錄父邊的權(quán)值preE[u]

再dfs2來更新得到正確的ans[u](即整棵樹以u為目標(biāo)節(jié)點(diǎn)的代價(jià))
即:ans[u]=ans[p]-sum[u]*preE[u]+(tot-sum[u])*preE[u];
這時(shí)ans[p]保存的是所有點(diǎn)到p的代價(jià),當(dāng)然包括從u的及其子樹到p的代價(jià),所以要減去
+除u的子樹外的所有節(jié)點(diǎn)到達(dá)u的代價(jià)

跟hdu 2196 poj 3585 CII 4614 一樣,2次dfs
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

const int MAXN = 100010;

vector<pair<int,int> >G[MAXN];

long long ans[MAXN],sum[MAXN];
long long tot;
int preE[MAXN],cnt[MAXN];

void dfs1(int u,int p)
  {
sum[u]=cnt[u];
ans[u]=0;
for(int i=0,size=G[u].size();i<size;i++)
 {
int v=G[u][i].first,c=G[u][i].second;
if(v==p)continue;
dfs1(v,u);
preE[v]=c;
sum[u]+=sum[v];
ans[u]+=(ans[v]+sum[v]*c);
}
}
void dfs2(int u,int p)
  {
if(u!=1)
 {
ans[u]=ans[p]-sum[u]*preE[u]+(tot-sum[u])*preE[u];
}
for(int i=0,size=G[u].size();i<size;i++)
 {
int v=G[u][i].first;
if(v==p)continue;
dfs2(v,u);
}
}
int main()
  {

int n;
int a,b,c;
while(~scanf("%d",&n))
 {
tot=0;
for(int i=1;i<=n;i++)
 {
G[i].clear();
scanf("%d",&cnt[i]);
tot+=cnt[i];
}
for(int i=1;i<n;i++)
 {
scanf("%d%d%d",&a,&b,&c);
G[a].push_back(make_pair(b,c));
G[b].push_back(make_pair(a,c));
}
preE[1]=0;
dfs1(1,0);
dfs2(1,0);
printf("%lld\n",*min_element(ans+1,ans+1+n));
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|