树形DP之自驾旅行

来源:互联网 发布:长沙启航学校网络教育 编辑:程序博客网 时间:2024/04/29 10:50

hihocoder – 1035
题目链接:http://hihocoder.com/problemset/problem/1035
题目类型:树形DP
DP类编程题目的关键是找到转移方程,本题转移方程的设计如下:
dsf[i][j]表示遍历完所有子树之后,某一个节点所处的状态,共分5种情况:
dsf[fa][0]:人去人不回,含义是从该节点出发,每条路径都是人走,最终人不返回该节点,而是停留在某一课子树当中;
dsf[fa][1]:人去人回,含义是从该节点出发,每条路径都是人走,最终人返回该节点;
dsf[fa][2]:人车去人车回,含义是从该节点出发,每条路径可以是人走,也可以驾车,但是最终要保证人车都处于该节点;
dsf[fa][3]:人车去人回,含义是从该节点出发,每条路径可以是人走也可以驾车,但是最终人处于该节点,车处于某颗子树当中;
dsf[fa][4]:人车都去,含义是从该节点出发,每条路径既可以人走,也可以乘车,最终人车都不在该节点,而是在某颗子树当中;
下面设计转移方程,w1(fa,son)、w2(fa,son)分别表示人走和乘车的代价:
1)dsf[fa][1] ,dsf[fa][2]:
dsf[fa][1] = ∑ dsf[son][1] + 2 w1(fa,son);
dsf[fa][2] = ∑ min(dsf[son][1] + 2 w1(fa,son) , dsf[fa][2] + 2 w2(fa,son));
2) dsf[fa][0]:
tmp = min( dsf[son[0] - w1(fa,son) - dsf[son][1]) ; tmp = min (tmp , 0)
dsf[fa][0] = dsf [fa][1] + tmp;
3)dsf[fa][3] :
t2 = min(2 w1(fa,son) + dsf[son][1] , 2 w2(fa,son) + dsf[son][2]);
t3 = 0 ; t2 = min (t3 , w1(fa,son) + w2(fa,son) + dsf[son] [3] - t2);
dsf[fa][3] = dsf[fa][2] + t2;
4)dsf[fa][4]分两种情况

  1. 走最后一棵树时还有车:
    tmp1 = min(w1(fa,son) + dsf[son][0],w2(fs,son) + dsf[son][4]),
    tmp2 = min (tmp1 - t2);
    tmp3 = min(0,tmp3);
    dsf[fa][4] = dsf[fa][2] + tmp3;
  2. 走最后一棵树时没车了:
    这种情况表示,在走最后一棵树之前走某一课子树时的情况是(w2(fa,son) + w1(fa,son) + dsf[son][3]),
    此时最后一棵树的决策是:
    (w1(fa,son) + dsf[son][0]);
    令 ff1 = w2(fa,son) + w1(fa,son) + dsf[son][3] - t2;
    ff2 = w1(fa,son) + dsf[son][0] - t2;
    求得ff1 + ff2 的最小值,则dsf[fa][4] = dsf[fa][2] + ff1 + ff2;
    C代码实现(手打,若有错误还请谅解):
#include<stdio.h>#include<stdlib.h>//定义最大节点个数 MAX_NUM#define MAX_NUM (1000000001)#define INF (1 << (30))//定义结点类型typedef struct node{    int c0,c1,v;    struct node * next;}node;//静态开辟节点存储空间node buf[2 * MAX_NUM];int buffsize = 0; // sp//定义节点数组node * head[MAX_NUM] = {NULL};//定义关键结点标记数组bool vis[MAX_NUM] ={false};//定义DP辅助结构int dp[MAX_NUM][5] = {0};//定义插入一条边的函数(将孩子、父亲节点插入孩子、父亲链表时,采用头插法)void insert(int u,int v,int c0,int c1){    //首先得到一个结点的空间指针    node * p = buf + buffsize ++;    {        p -> c0 = c0;        p -> c1 = c1;        p -> v = v;        p -> next = head[u];    }    {        p = buf + buffsize ++;        p ->c0 = c0;        p -> c1 = c1;        p -> v = u;        p -> next = head[v];        head[v] = p;    }}//树形DP处理函数void dsf(int u,int fa){    node * p = head[u];    for(;p != NULL; p = p -> next)    {        int v = p -> v;        if(v == fa) continue;        dsf(v,u);        vis[u] |= vis[v];    }    if(vis[u] == true)    {        dp[u][0] = dp[u][1] = dp[u][2] \        = dp[u][3] = dp[u][4] =0;        p = head[u] ;        //求dp[u][1];        for(;p;p = p ->next)        {            int v = p -> v;            if(v == fa) continue;            if(vis(v))            {            tmp2 = min(2 * p -> c0 + dp[v][1],                2 * p -> c1 + dp[v][2]);            dp[u][1] += dp[v][1] + (2 * p -> c0);            dp[u][2] += tmp2;            tmp0 =             min(tmp0,dp[v][0] - dp[v][1] - p -> c0);            tmp3 =            min(tmp3,p -> c1 + p -> c0 +dp[v][3] - tmp2);            tmp41 =             min(tmp41,min(p -> c0 + dp[v][0],                      p -> c1 + dp[v][4]) - tmp2);            ff1 = p -> c0 + p -> c1 + dp[v][3] - tmp2;            ff2 = p -> c0 + dp[v][0] - tmp2;            if(ff1 < t1)            {                match1 = v;                t2 = t1;                t1 = ff1;            }            else t2 = min(ff1,t1);            if(ff2 < f1)            {                match2 = v;                f2 = f1;                f1 = ff2;            }            else f2 = min(f1,ff2);            }        }    }}
0 0
原创粉丝点击