树形DP <dfs+floyd> 【hlg】 1329 游乐园

题意:

给出修建每一段距离所要花费的钱..d(len) = cost

给出修建一个游乐园的花费 k 

给出连通的城市编号..<保证每两个城市之间只有一条路..>


思路:

先说树形DP吧~

       教主大人语录:

              因为由题意画图可知是一棵树..所以只能是图论和DP..

              而DP问题可解决类似暴力解决的问题..

       所以..这道奇怪的题就是DP了..

       =è>>>其实树形DP和正常DP不同在于DP的时候要给一个限定条件..即是否相连..在一个图中画出一棵树..然后for循环遍历所有相连的點..并且进行动态转移..

 

       其中用到了dfs

Dfs的作用是深度遍历这棵树..然后确定动态转移需要用到的状态..

注意就是哨兵变量flag用来标记是不是到叶结点了..

 

Dfs函数主要完成的几样功能是:

       从根节点开始搜索它的子节点然后对其深搜..

       如果是叶结点就确定相关的状态<f[r][i] &&opt[r] = r>..

       如果不是叶结点就开始最关键的状态转移

              先从相连的节点开始遍历..假设这是最优方案..那就遍历别的點并计算出f[r][i]..

              更新信息..<tmp & opt>以确定后面的状态转移时需要的状态..

 

       还用到了floyd..

总用是确定用题目给出的两个點的信息画出树..

先用数组len[u][v]标记两个点是否相连..其中因为给出的顺序是不一定的..不能肯定谁是父谁是子..所以标记时是len[u][v] = len[v][u] = 1;

而后用floyd建一棵树..因为是3层for循环..所以不用len[i][j] = lenp[j][i] = ~

 

主要用到的算法就是这些了~

 

Code..

#include <stdio.h>
#include <cstring>
#define INF 0x1f1f1f1f
#define min(a, b) a<b?a:b
 
int T, n, k;
int len[210][210], f[210][210];
int opt[210], d[210];
bool f_lag[210];
 
void dfs(int r)
{
   bool flag = false;///!!! pay attention to this variable must be signedas local variable
   f_lag[r] = true;
   for(int i = 1; i <= n; ++i){
       if(len[r][i] == 1 && !f_lag[i]){
           flag = true;
           dfs(i);
       }
    }
 
   if(!flag){///affect the node which is leaf node
       for(int i = 1; i <= n; ++i)
           dp[r][i] = d[len[r][i]];
       opt[r] = r;  ///this part is justaffect the leaf node, so its optimal solution its itself
       return;
    }
 
   int tmp = INF;
   ///***affect the node which isn't leaf node***///
   for(int i = 1; i <= n; ++i){///assume one leaf node as its optimalnode, figure out ans of the other node while its optimal solution is it,too
       dp[r][i] = d[len[r][i]];
 
       for(int j = 1; j <= n; ++j)
       if(len[r][j] == 1 && opt[j] != 0)
       dp[r][i] += min(dp[j][i], dp[j][opt[j]] + k);
 
       if(dp[r][i] < tmp){
           opt[r] = i;
           tmp = dp[r][i];
       }
    }
}
 
int main()
{
   int i, j, ii;
   int u, v;
   while(scanf("%d", &T) != EOF)
   while(T--)
    {
       memset(dp, 0, sizeof(dp));
       memset(len, 0, sizeof(len));
       memset(opt, 0, sizeof(opt));
       memset(f_lag, false, sizeof(f_lag));
       scanf("%d %d", &n, &k);
       for(i = 1; i < n; ++i){
           scanf("%d", &d[i]);
       }
       for(i = 1; i < n; ++i){
           scanf("%d%d", &u, &v);
            len[u][v] = len[v][u] = 1;
        }
 
       for(ii = 1; ii <= n; ++ii)///use the floyd figure out the distancebetween conjoint node 
                                   ///***assum as a circle, link diffrient son node, ii is thecentre of the circle***///
       for(i = 1; i <= n; ++i)
       if(len[i][ii])
       for(j = 1; j <= n; ++j)
       if(i != j && len[ii][j] && len[i][j] == 0)
       len[i][j] = len[i][ii]+len[ii][j];
 
       dfs(1);
       printf("%d\n", dp[1][opt[1]]+k);
                     ///because this algotithm isbased on a tree, so while cout the ans, we should cout the father node..
    }
   return 0;
}
 



Tips:

初始条件:leaf 表示叶节点.. 

                               dp[ leaf ][ i ] = d[ len[ leaf ][ i ] ]                   opt[ r ] = r

动态转移方程: if(len[r][j] == 1 && opt[j] != 0)
                                     dp[r][i] += min(dp[j][i], dp[j][opt[j]] + k);

结果:dp[ 1 ][ opt[1]  ] + k

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值