题意:
给出修建每一段距离所要花费的钱..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