序:
近来,做pat发现了两种dfs的写法有些微区别。一种是定长path,用覆盖法深搜;另一种是不定长path,用push_back和pop_back进行回溯。
见下面两个函数:
1.定常path
void dfs(int nodeid, int nodesum, int totalsum)
{
//先判断后深搜
if(totalsum > target) return;
else if(totalsum == target)
{
//若非叶子
if(v[nodeid].son.size() != 0) return;
for(int i = 0; i < nodesum; i++)
{
if(i != nodesum - 1) cout << v[path[i]].w << " ";
else cout << v[path[i]].w << endl;
}
return;
}
else
{
for(int i = 0; i < v[nodeid].son.size(); i++)
{
int sonnodeid = v[nodeid].son[i];
path[nodesum] = sonnodeid;
dfs(sonnodeid, nodesum + 1, totalsum + v[sonnodeid].w);
}
}
}
2.不定长path
void dfs(int v)
{
temppath.push_back(v);
//如果反向dfs到达起点,已经保证是最短路径
if(v == 0)
{
int need = 0, back = 0;
//从起点开始遍历
for(int i = temppath.size() - 1; i >= 0; i--)
{
int id = temppath[i];//注意是temppath对应的序号
if(weight[id] >= 0)
{
back += weight[id];
}
else
{
//如果back足够抵消亏损
if(back >= -weight[id])
back += weight[id];
else
{
need += -weight[id] - back;
back = 0;
}
}
}
//与min比较
if(need < minneed)
{
minneed = need;
minback = back;
path = temppath;
}
else if(need == minneed && back < minback)
{
minback = back;
path = temppath;
}
//回溯
temppath.pop_back();
return;
}
//正常遍历
for(int i = 0; i < pre[v].size(); i++)
dfs(pre[v][i]);
//回溯
temppath.pop_back();
return;
}
问题来了:为什么不定长要回溯?
我们通过分析,知道定长的这种写法只有一个变量,覆盖地按顺序深搜。
而不定长的,倘若没有pop_back机制,那么其他解法就会被忽略(如一路多解),因此,在多种的解下必须考虑pop_back。这是为了考虑所有合理解。
总结,定长在遍历中直接进行覆盖;不定长在遍历外push&pop。