树形DP
1. HDU 2196 题目:求出一棵树上的所有点到其他点的最长距离。
思路:取一个根节点进行dfs,先求出每个节点到子节点的最长路和次长路(也就是与最长路不同的最长的路,有可能与最长路长度相等),并记录最长路和次长路通过的相邻节点的标号。然后进行第二次dfs,考虑最长路是通过父节点的情况,如果该节点v在父节点的最长路上,那么需要取次长路,否则就取最长路。
第二次dfs的时候最长路的通过节点还是要更新,因为若某个父节点的最长路是朝祖先走的,那么其子节点的最长路一定朝祖先走,且与v是否在父节点向下的最长路上无关。
#include<iostream> #include<map> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<queue> #include<stack> #include<functional> #include<set> #include<cmath> #define pb push_back #define fs first #define se second #define sq(x) (x)*(x) #define eps 0.0000000001 using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int maxv=1e4+300; int N; vector<P> G[maxv]; int maxd[maxv],maxdn[maxv],smaxd[maxv],smaxdn[maxv]; void dfs1(int u,int f){ maxd[u]=smaxd[u]=0; for(int i=0;i<G[u].size();i++){ int v=G[u][i].fs; int len=G[u][i].se; if(v==f) continue; dfs1(v,u); if(len+maxd[v]>smaxd[u]){ smaxd[u]=len+maxd[v]; smaxdn[u]=v; } if(smaxd[u]>maxd[u]){ swap(smaxd[u],maxd[u]); swap(smaxdn[u],maxdn[u]); } } } void dfs2(int u,int f){ for(int i=0;i<G[u].size();i++){ int v=G[u][i].fs; int len=G[u][i].se; if(v==f) continue; if(maxdn[u]==v){ if(smaxd[u]+len>smaxd[v]){ smaxd[v]=smaxd[u]+len; smaxdn[v]=u; } if(smaxd[v]>maxd[v]){ swap(maxd[v],smaxd[v]); swap(maxdn[v],smaxdn[v]); } }else{ if(maxd[u]+len>smaxd[v]){ smaxd[v]=maxd[u]+len; smaxdn[v]=u; } if(smaxd[v]>maxd[v]){ swap(maxd[v],smaxd[v]); swap(maxdn[v],smaxdn[v]); } } dfs2(v,u); } } int main(){ /////freopen("/home/files/CppFiles/in","r",stdin); /* std::ios::sync_with_stdio(false); std::cin.tie(0);*/ while(cin>>N){ for(int i=1;i<=N;i++) G[i].clear(); for(int i=2;i<=N;i++){ int a,b; scanf("%d%d",&a,&b); G[i].pb(P(a,b)); G[a].pb(P(i,b)); } dfs1(1,-1); dfs2(1,-1); for(int i=1;i<=N;i++){ printf("%d\n",maxd[i]); } } return 0; }
2. HDU 5290
题目:每个节点有一个爆炸范围,要求用最少的节点炸掉所有节点.
思路:维护up,down两个dp数组,分别表示还能向上炸的,以及下方有部分节点没有炸的最小花费...wa了很久,是因为没有用up[v][0]去更新down,其实这和用up更新up的部分是一样的.
/* * @author: Cwind */ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define INF (1000000300) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,string> P; const int maxn=1e5+300; int n; int w[maxn]; ll down[maxn][102],up[maxn][102]; vector<int> G[maxn]; void dfs(int v,int f=-1){ ll sum=0; clr(down[v]); for(int i=0;i<=100;i++) up[v][i]=n; for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; dfs(u,v); for(int j=1;j<=100;j++) down[v][j]+=down[u][j-1]; down[v][0]+=up[u][0]; if(w[v]>0) sum+=down[u][w[v]-1]; else sum+=up[u][0]; } for(int i=0;i<G[v].size();i++){ int u=G[v][i]; if(u==f) continue; up[v][0]=min(up[v][0],up[u][1]+down[v][0]-up[u][0]); for(int j=1;j<100;j++) if(up[u][j+1]<1e8) up[v][j]=min(up[v][j],up[u][j+1]+down[v][j]-down[u][j-1]); } up[v][w[v]]=min(up[v][w[v]],sum+1); for(int i=99;i>=0;i--) up[v][i]=min(up[v][i],up[v][i+1]); down[v][0]=min(down[v][0],up[v][0]); for (int i = 1; i <= 100; i++)down[v][i] = min(down[v][i], down[v][i - 1]); } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("/home/slyfc/CppFiles/out","w",stdout); while(cin>>n){ for(int i=0;i<maxn;i++) G[i].clear(); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=0;i<n-1;i++){ int a,b; scanf("%d%d",&a,&b); G[a].pb(b);G[b].pb(a); } dfs(1); printf("%d\n",(int)up[1][0]); } return 0; }