hdu 1520
题意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少?
题解:树形DP入门题。由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优。其实不然,有可能父节点和子节点都不选,而要选子孙节点。不过只要再往深点想下,就可以得出动态规划的解法。每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那我们只要从叶子节点往根结点不断更新dp[i][0]和dp[i][1]就可以了。
状态转移方程:dp[i[[1] = sum(dp[j][0]) (当前选了,子节点必定不能选,最优的情况是都不选,然后累加)
dp[i][0] = sum(max(dp[i][0],dp[i][1])) (当选不选,子节点可选可不选,找大的那个状态)
struct Edge{
int v,next;
}edge[MAX*2];
int dp[MAX][2];
int vis[MAX];
int head[MAX];
int n;
int tot;
void add_edge(int a,int b){
edge[tot]=(Edge){b,head[a]};
head[a]=tot++;
}
void tree_dp(int u){
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(!vis[v]){
tree_dp(v);
dp[u][1]+=dp[v][0];
dp[u][0]+=max(dp[v][1],dp[v][0]);
}
}
}
int main(){
while(~scanf("%d",&n)){
mem0(dp);
mem0(vis);
mem1(head);
tot=0;
for(int i=1;i<=n;i++) scanf("%d",&dp[i][1]);
int a,b;
while(scanf("%d%d",&a,&b)&&a&&b){
add_edge(a,b);
add_edge(b,a);
}
tree_dp(1);//把1当作根
printf("%d\n",max(dp[1][1],dp[1][0]));
}
return 0;
}
hdu 2196
题意:给你n-1条边,每条边有权值,然后求从任意一个点开始到底的最长路径
题解:这题和树的直径挺像的,求从i点开始的最长路径,这个路径要么经过i的父节点,要么经过i的子节点,所以可以用两次dfs来维护从i开始的最长路径和次长路径(为什么要记录次长路,看代码理解比较快,因为在考虑从它父节点过来的距离的时候,如果它就是它父节点上的最长路径上的一点,那么必须考虑父节点的次长路径)
struct Edge{
int v,cost,next;
}edge[MAX*2];
int maxn[MAX];
int maxid[MAX];
int smaxn[MAX];
int smaxid[MAX];
int head[MAX];
int n;
int tot;
void add_edge(int a,int b,int c){
edge[tot]=(Edge){b,c,head[a]};
head[a]=tot++;
}
void dfs1(int u,int fa){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
int c=edge[i].cost;
if(v==fa) continue;
dfs1(v,u);
if(smaxn[u]maxn[u]){
swap(smaxn[u],maxn[u]);
swap(maxid[u],smaxid[u]);
}
}
}
}
void dfs2(int u,int fa){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
int c=edge[i].cost;
if(v==fa) continue;
if(v==maxid[u]){
if(smaxn[v]maxn[v]){
swap(smaxn[v],maxn[v]);
swap(maxid[v],smaxid[v]);
}
}
}
else{
if(smaxn[v]maxn[v]){
swap(smaxn[v],maxn[v]);
swap(maxid[v],smaxid[v]);
}
}
}
dfs2(v,u);
}
}
int main(){
while(~scanf("%d",&n)){
mem1(head);
mem0(smaxn);
mem0(maxn);
mem0(maxid);
mem0(smaxid);
tot=0;
for(int i=2;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
add_edge(i,a,b);
add_edge(a,i,b);
}
dfs1(1,-1);
dfs2(1,-1);
for(int i=1;i<=n;i++) printf("%d\n",maxn[i]);
}
return 0;
}