(30)分水了啊。
题意
给定一棵树和每个结点的权值,求所有从根结点到叶子结点的路径,使得每条路径上结点的权值之和等于给定的常数S。如果有多条这样的路径,按路径非递增的顺序输出。
其中路径的大小是指,如果两条路径分别为(a_l→a_2→cdots→a_i→a_n)与(b_1→b_2→cdots→b_i→b_m),且有(a_1=b_1、a_2=b_2cdots 、a_{i-1}=b_{i-1})成立,但(a_i>b_i),那么称第一条路径比第二条路径大。
思路
- 若sum>S,直接return。
- 若sum==S,说明到当前访问结点index为止,输入中需要达到的S已经得到,这时如果结点index为叶子结点,则输出path数组中的所有数据;否则return。
- 若sum<S,说明要求还未满足。此时枚举当前访问结点index的所有子结点,对每一个子结点child,先将其存入path,然后在此基础上往下一层递归。
注意点
- vector是可以直接比较大小的,比较标准为字典序。
- 题目要求是从根结点到叶结点的路径,所以在递归过程中出现sum = S时必须判断当前访问结点是否是叶结点(即是否有子结点)。只有当前访问结点不是叶结点,才能输出路径,如果不是叶结点,则必须返回。
const int N=110;
vector<int> g[N];
int weight[N];
vector<vector<int>> ans;
vector<int> res;
int n,m,target;
void dfs(int u,int sum)
{
if(sum > target) return;
if(sum == target)
{
if(g[u].size() == 0)
ans.push_back(res);
return;
}
for(int i=0;i<g[u].size();i++)
{
int j=g[u][i];
res.push_back(weight[j]);
dfs(j,sum+weight[j]);
res.pop_back();
}
}
int main()
{
cin>>n>>m>>target;
for(int i=0;i<n;i++) cin>>weight[i];
while(m--)
{
int u,k;
cin>>u>>k;
for(int i=0;i<k;i++)
{
int v;
cin>>v;
g[u].pb(v);
}
}
res.pb(weight[0]);
dfs(0,weight[0]);
sort(ans.begin(),ans.end(),greater<vector<int>>());
for(auto &v:ans)
{
for(int i=0;i<v.size();i++)
if(i) cout<<' '<<v[i];
else cout<<v[i];
cout<<endl;
}
//system("pause");
return 0;
}
考虑到最后的输出需要按权值从大到小排序,也可以在读入时就事先对每个结点的子结点vector进行排序(即对vector中的结点按权值从大到小排序),这样在遍历时就会优先遍历到权值大的子结点。