第36届ACM国际大学生程序设计竞赛亚洲区预赛北京邀请赛 A
我用的是记忆化搜索来实现树状DP。
首先以点1为根进行建树。然后dp[i][0],dp[i][1] 记录的是以i为根的,到其子树的叶子结点的两个最小的距离
注意i有0个或1个子树的情况,还要注意1这个根节点的子树情况。
最后搜索一遍dp[i][0]+dp[i][1],取最小值。
1Y,可是发现时间并不是很快,500多ms。可能是我用了vector的原因,还是什么情况?
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <string.h> #include <vector> using namespace std; const int maxn = 10005; const int maxint = 2147483647; struct Info { int v; int d; }; vector<Info>v[maxn]; vector<Info>vv[maxn]; int vis[maxn]; int dp[maxn][2]; int n,mins; void dfs(int u) { vis[u]=true; for(int i=0;i<(int)v[u].size();i++) { if(!vis[v[u][i].v]) { Info tmp; tmp.v=v[u][i].v; tmp.d=v[u][i].d; vv[u].push_back(tmp); dfs(v[u][i].v); } } } int Cal_dp(int u) { if(vv[u].size()==0) return 0; for(int i=0;i<(int)vv[u].size();i++) { int t=Cal_dp(vv[u][i].v); if(t+vv[u][i].d<dp[u][1]) dp[u][1]=t+vv[u][i].d; if(dp[u][0]>dp[u][1]) swap(dp[u][0],dp[u][1]); } return dp[u][0]; } int main() { int a,b,c; Info tmp; while(scanf("%d",&n) && n!=0) { for(int i=1;i<=n;i++) { v[i].clear(); vv[i].clear(); } for(int i=1;i<=n-1;i++) { scanf("%d %d %d",&a,&b,&c); tmp.v=b; tmp.d=c; v[a].push_back(tmp); tmp.v=a; tmp.d=c; v[b].push_back(tmp); } memset(vis,false,sizeof(vis)); dfs(1); for(int i=1;i<=n;i++) { if(vv[i].size()==0) dp[i][0]=0,dp[i][1]=0; else dp[i][0]=maxint,dp[i][1]=maxint; } if(n==2) { printf("%d\n",vv[1][0].d); continue; } for(int i=0;i<(int)vv[1].size();i++) { int t=Cal_dp(vv[1][i].v); if(t+vv[1][i].d<dp[1][1]) dp[1][1]=t+vv[1][i].d; if(dp[1][1]<dp[1][0]) swap(dp[1][1],dp[1][0]); } int mins = maxint; if(vv[1].size()==1) { if(dp[1][0]<mins) mins=dp[1][0]; } for(int i=1;i<=n;i++) { if(vv[i].size()==0 || vv[i].size()==1) continue; if(dp[i][0]+dp[i][1]<mins) mins=dp[i][0]+dp[i][1]; } printf("%d\n",mins); } return 0; }