类型:图论 难度:2
题意:发电站和各级变压器构成一棵树的节点,发电站为根节点。现在需要从根节点出发,沿树边检查每个节点,必要时回溯,检查完最后一个节点立即终止,给出每条边的耗时/路径长,求最短耗时/最短路径。
分析:由于要遍历所有节点,所有假设根节点有n个子树,只有走最后一棵子树时不用回溯到根节点。其余n-1棵子树均需回到根节点,则其余n-1棵子树所走的路径长即为:(每棵子树的路径和+根节点到该儿子的路径)*2,而第n棵子树的路径长即为:根节点到该儿子的路径+将该点作为根节点继续递归求解的路径。所以一开始以递归问题做的。但是不难发现,整体上看,走完所有节点后,只有一条从根节点到叶子节点的路径走了1次,其余所有路径均走了两次,而这条路径即为所有从根节点到叶子节点的路径中最长的路径,所以问题转化为找此最长路径,再用 总路径长*2-最长路径 即为所求,思路更简单。
具体实现上,用dfs遍历记录每个根节点到叶子的路径长,选最大即可
代码如下:
#include<cstring>
#include<string>
#include<cstdio>
#include<sstream>
#include<iostream>
#include<vector>
#include<map>
using namespace std;
const int MAX = 55;
class PowerOutage
{
public:
int par[MAX],chd[MAX],bro[MAX],len[MAX];
int edge[MAX][MAX];
int maxlen;
void dfs(int root)
{
for(int i=chd[root]; i>=0; i=bro[i])
{
len[i] = len[root]+edge[root][i];
if(chd[i] < 0)
{
if(len[i] > maxlen)
maxlen = len[i];
}
else
dfs(i);
}
}
int estimateTimeOut(vector <int> fromJunction, vector <int> toJunction, vector <int> ductLength)
{
int n=fromJunction.size();
int i;
int sumlen=0;
memset(par,-1,sizeof(par));
memset(chd,-1,sizeof(chd));
memset(bro,-1,sizeof(bro));
memset(len,0,sizeof(len));
memset(edge,-1,sizeof(edge));
for(i=0; i<n; i++)
{
par[toJunction[i]] = fromJunction[i];
if(chd[fromJunction[i]] >= 0)
{
bro[toJunction[i]] = chd[fromJunction[i]];
}
chd[fromJunction[i]] = toJunction[i];
edge[fromJunction[i]][toJunction[i]] = ductLength[i];
sumlen += ductLength[i];
}
maxlen = 0;
dfs(0);
return sumlen*2-maxlen;
}
};