Problem 0235 : Sergeant Rian
解法
グラフをノード1を根とする木と考える。
dp[i]を、i以下のサブツリーのエッジを全て爆破してiに戻ってくるのにかかる最小の時間とする。
また、dp2[i]を、i以下のサブツリーのエッジを全て爆破するのにかかる最小の時間とする。
子をもたないノードは訪れる必要がないので、
dp[i]はΣ{d[i][j]*2+dp[j]|jはiの子のうち子をもつノード}となる。
dp2[i]は、dp[i]のうち、どこか一つのノードへ行ったきり戻ってこない(他のノードからは爆破後戻ってくる)ときのコストである。
よってdp2[i]はmin{dp[i]-(jに行かなかったことにする)+dp2[j]|jはiの子のうち子を持つノード}
と書ける。
以上の漸化式でDPすればよい。
ソースコード
const int inf=1<<29; int n,dp[100],dp2[200]; vector<vector<pair<int,int> > > e; void rec(int c,int p){ fr(i,e[c])if(i->first!=p&&e[i->first].size()>1){ rec(i->first,c); dp[c]+=2*i->second+dp[i->first]; } dp2[c]=dp[c]; fr(i,e[c])if(i->first!=p&&e[i->first].size()>1){ dp2[c]=min(dp2[c],dp[c]-i->second-dp[i->first]+dp2[i->first]); } } int main(){ while(cin>>n,n){ e.clear(); e.resize(n); rep(i,n-1){ int a,b,t; cin>>a>>b>>t; a--; b--; e[a].pb(mp(b,t)); e[b].pb(mp(a,t)); } rep(i,n)dp[i]=0,dp2[i]=inf; rec(0,-1); cout<<dp2[0]<<endl; } return 0; }