pku 树形dp 1849 two 解题报告

来源:互联网 发布:淘宝拍摄报价单 编辑:程序博客网 时间:2024/06/06 08:40

 

pku 1849 two 解题报告

题目链接: http://acm.pku.edu.cn/JudgeOnline/problem?id=1849

题意:

给出一棵树的公路网,公路网堆满雪,需要2辆汽车扫完全部雪,树的权值表示耗费汽车的油费,求汽车从结点S开始,用最少汽油费扫完全部雪,汽油费是多少?

思路:

通过此题,更加深刻了解树形dp的特点,树形dp通常是典型的从低向上dp,解决数据大,是树形结构的。解决问题的关键在于寻找其状态方程,然后用深度搜索搜到树低,然后利用状态转移方程一步一步往上dp

     由于题目只是要求2辆汽车,那么我们想想,如果S只有一棵子树,出现的情况可能就是1辆汽车走到底或者2辆汽车走到底.再深入一步想,有两棵子树呢?就应该2辆汽车各走一个子树。3棵子树呢?就应该有1可子树是最短的而且走2,以此类推456```棵子树的情况,只要先求出最短2棵子树的路径,那么所有子树的路径之和*2-2棵最短路径子树之和即为答案.那么状态转移方程就出来了: ji的儿子

dp[i][1]=2*j->Distance+dp[j][1]      //1辆汽车去一棵子树了又返回其结点

dp[i][2]= min(dp[i][1]+ dp[j][2] - dp[j][1] - j->Distance)   //1辆汽车去了子树不返回其结点

dp[i][3]=min(dp[i][1] +dp[j][3] - dp[j][1]- LongestPath - MinisterPath)//2辆汽车去了子树都不返回其结点

 

AC代码:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define M 100005

 

typedef struct node

{

       int Point, Distance;

       struct node *next;

}*adjv;

adjv tree[M];

int N, S;

bool visit[M];             //对结点的访问

int dp[M][3];              //只需要记录三条路径 1:1--->1(1人去同时此人回到原点), 2:1---->0(1人去同时此人不回来), 3:2---->0(2人去同时2人都不回来)

 

void input()

{

       int i, a, b, c;

 

       for (i = 1; i <= N; i++)

       {

              tree[i] = NULL;

       }

       for (i = 1; i < N; i++)

       {

              //用链接表保存这棵树

              scanf("%d%d%d", &a, &b, &c);

              node *temp = new node;

              temp->Point = b; temp->Distance = c; temp->next = NULL;

              if (tree[a] == NULL)

              {

                     tree[a] = temp;

              }

              else

              {

                     node *tmp = tree[a];

                     while (tmp->next)

                     {

                            tmp = tmp->next;

                     }

                     tmp->next = temp;

              }

              temp = new node;

              temp->Point = a; temp->Distance = c; temp->next = NULL;

              if (tree[b] == NULL)

              {

                     tree[b] = temp;

              }

              else

              {

                     node *tmp = tree[b];

                     while (tmp->next)

                     {

                            tmp = tmp->next;

                     }

                     tmp->next = temp;

              }

       }

}

 

//   dp方程是dp[k][i][j]表示以第k个点为子树的去了i个人回来j个人的最小花费

//   这样需要对3i,j的值进行计算,不难看出是1 0, 1 1, 2 0,

void dfs(int point)

{

       visit[point] = true;

       int SavePath[M];

       node *temp = tree[point];

       //一人去一人返回

       dp[point][1] = 0;

       int i, min1 = 0, min2 = 0, count = 0;

       while (temp)

       {

              if (!visit[temp->Point])

              {

                     //深度搜索搜索到树低

                     dfs(temp->Point);

                     //1----->1  路径*2+儿子回来的路径

                     dp[point][1] += 2 * temp->Distance + dp[temp->Point][1];

                     //画图可知,求出point1人回来与1人不回来的差值

                     if (min1 > dp[temp->Point][2] - dp[temp->Point][1] - temp->Distance)

                     {

                            min1 = dp[temp->Point][2] - dp[temp->Point][1] - temp->Distance;

                     }

                     //画图可知,求出point2人回来与2人不回来的差值

                     if (min2 > dp[temp->Point][3] - dp[temp->Point][1])

                     {

                            min2 = dp[temp->Point][3] - dp[temp->Point][1];

                     }

                     SavePath[count++] = dp[temp->Point][2] - dp[temp->Point][1] - temp->Distance;

              }

              temp = temp->next;

       }

       //1人不回来的数值

       dp[point][2] = dp[point][1] + min1;

       int LongestPath = 0, MinisterPath = 0;

       //如果儿子大于2的话,即子树>=2,那么最佳路径就是所有子树路径*2-2条最长路径,2人也不用回来.

       if (count > 1)

       {

              for (i = 0; i < count; i++)

              {

                     if (SavePath[i] < LongestPath)

                     {

                            MinisterPath = LongestPath;

                            LongestPath = SavePath[i];

                     }

                     else if (SavePath[i] < MinisterPath)

                     {

                            MinisterPath = SavePath[i];

                     }

              }

              min2 = ((LongestPath + MinisterPath) < min2 ? (LongestPath + MinisterPath) : min2);

       }

       dp[point][3] = dp[point][1] + min2;

}

 

int min(int a, int b, int c)

{

       int temp = a > b ? b : a;

       return temp > c ? c : temp;

}

 

int main()

{

       //freopen("1.txt", "r", stdin);

       scanf("%d%d", &N, &S);

       input();

       dfs(S);

       //答案取3种情况的最优值

       int ans = min(dp[S][1], dp[S][2], dp[S][3]);

       printf("%d/n", ans);

       return 0;

}

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 成熟卵泡打破卵针也不破怎么办? 深圳孩子户口挂别人名下上学怎么办 襄阳东风合运花园房贷怎么办下来 猫在外面躲起来找不到了怎么办 本科三批取消以后三本学校怎么办 机票名字多了个字母安检怎么办 出隧道口限速40超速了怎么办 社保交了五年后断交以后该怎么办 躺椅折叠椅坐的地方坏了怎么办 苹果手机锁频密码忘了怎么办 客户要货公司不给进怎么办 高铁23:00买的票怎么办 带电子手刹的车刹车失灵怎么办 下坡刹车失灵遇行人不看车怎么办 跟大车后面看不见红灯闯了怎么办 跟着大货车后面闯了红灯怎么办 如果用工单位不发放加班工资怎么办 事故家属要司机向医院多交钱怎么办 在大学里和室友关系弄僵怎么办 房产证办出来房产局不给证怎么办 单位全员竞聘老员工没岗位怎么办 快件被快递公司签收了没给送怎么办 总公司跑路了分公司代理法人怎么办 大使馆领的结婚证现在离婚怎么办 日本签证照片被使馆贴错了怎么办 在菲律宾护照和签证丢了怎么办 新疆工地上班老板不肯发工资怎么办 德国大使馆签证如果拒签了怎么办 护照在大使馆办签证期间出国怎么办 法院两次判决不准离婚我该怎么办? 法院判决不准离婚妻子不回来怎么办 被告人在不调解的情况下怎么办 知道弟兄的孩子是别人的怎么办? 办居住证的回执单丢了怎么办 领取居住证的回执单丢了怎么办 北京居住证网上申报信息填错怎么办 买家退回来的货有问题怎么办 居转户过程中生的小孩户口怎么办 人才引进申请上海户口被拒怎么办 网络购高铁票身份证没有验证怎么办 高速遇到很浓的团雾怎么办