PAT(A) - 1053 Path of Equal Weight (30) -- 活用sort()及注意

1053 Path of Equal Weight (30) – 活用sort()及注意

Given a non-empty tree with root R, and with weight W~i~ assigned to each tree node T~i~. The weight of a path from R to L is defined to be the sum of the weights of all the nodes along the path from R to any leaf node L.

Now given any weighted tree, you are supposed to find all the paths with their weights equal to a given number. For example, let’s consider the tree showed in Figure 1: for each node, the upper number is the node ID which is a two-digit number, and the lower number is the weight of that node. Suppose that the given number is 24, then there exists 4 different paths which have the same given weight: {10 5 2 7}, {10 4 10}, {10 3 3 6 2} and {10 3 3 6 2}, which correspond to the red edges in Figure 1.

Figure1

\Figure 1

Input Specification:

Each input file contains one test case. Each case starts with a line containing 0 < N <= 100, the number of nodes in a tree, M (< N), the number of non-leaf nodes, and 0 < S < 2^30^, the given weight number. The next line contains N positive numbers where W~i~ (&lt1000) corresponds to the tree node T~i~. Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]

where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID’s of its children. For the sake of simplicity, let us fix the root ID to be 00.

Output Specification:

For each test case, print all the paths with weight S in non-increasing order. Each path occupies a line with printed weights from the root to the leaf in order. All the numbers must be separated by a space with no extra space at the end of the line.

Note: sequence {A~1~, A~2~, …, A~n~} is said to be greater than sequence {B~1~, B~2~, …, B~m~} if there exists 1 <= k < min{n, m} such that A~i~ = B~i~ for i=1, … k, and A~k+1~ > B~k+1~.

Sample Input:

20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
00 4 01 02 03 04
02 1 05
04 2 06 07
03 3 11 12 13
06 1 09
07 2 08 10
16 1 15
13 3 14 16 17
17 2 18 19

Sample Output:

10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2

大致题意为:给出一棵树,每个节点都有权重,若从根节点到叶节点路径的权重和为给定的一个数字的话,就输出这条路径上的权重,路径不唯一。(结合图片理解很清晰,Pintia原图基本都挂)

分析:路径搜索问题,此处显然dfs,直接上代码。

#include <iostream>  
#include <cstdio>
#include <string>
#include <cstring>
#include <vector> 
#include <cmath>  
#include <algorithm> 
using namespace std;  

vector<int> tab[105];
vector<vector<int> >output;
int power[105] = { 0 };
int n, m, s;

void dfs(vector<int> str, int now, int sum)  // 深度优先遍历,搜索符合要求路径
{
    sum = sum + power[now];       // 进入结点,先计算当前权值和
    str.push_back(power[now]);    // 结点入队,此为当前路线结点队列
    if (sum > s)return;           
    if (tab[now].size() == 0)
    {
        if (sum == s)
        {
            output.push_back(str);  //  利用全局变量记录符合要求路线
        }
        return;
    }
    for (int i = 0; i < tab[now].size(); i++)
    {
        dfs(str, tab[now][i], sum);
    }
}

bool cmp(vector<int> &a, vector<int> &b)  // 排序规则
{
    int len = min(a.size(), b.size());
    for (int i = 0; i < len; i++)
    {
        if (a[i] == b[i])continue;
        else return a[i] > b[i];
    }
    return 0;    // 此处必须返回0
}

int main() 
{
    // **********输入及建树部分**********
    scanf("%d %d %d", &n, &m, &s);
    for (int i = 0; i < n; i++)scanf("%d", &power[i]);
    for (int i = 0; i < m; i++)
    {
        int parent,sons;
        scanf("%d %d", &parent, &sons);
        for (int j = 0; j < sons; j++)
        {
            int s;
            scanf("%d", &s);
            tab[parent].push_back(s);
        }
    }
    // **********寻找符合要求路径部分**********
    vector<int> t;
    t.push_back(power[0]);
    for (int i = 0; i < tab[0].size(); i++)
    {
        dfs(t, tab[0][i], power[0]);
    }
    if (tab[0].size() == 0) // 必须特判根节点无子情况,负责测试点2不通过
    {
        if (power[0] == s)output.push_back(t);
    }
    // **********按要求输出部分**********
    sort(output.begin(), output.end(), cmp);
    for (int i = 0; i < output.size(); i++)
    {
        printf("%d", output[i][0]);
        for (int j = 1; j < output[i].size(); j++)
        {
            printf(" %d", output[i][j]);
        }
        printf("\n");
    }
    return 0;
}

由于结点规模在100以下,我利用vector数组存储每个结点的孩子。深度优先遍历提取所有可能路线,再对路线进行排序。

  • 学会活用sort排序,sort中的cmp函数由自己定义,不仅仅可以实现多属性的排序。对于本题,题目中已经严格给出了对路径大小的定义,可以写出两个vector之间的比较关系,实现cmp函数。

  • 注意:可能会遇见一下错误:

    bug

    return (_Pred(_Left, _Right)  // 引发断点
        ? (_Pred(_Right, _Left)
            ? (_DEBUG_ERROR2("invalid comparator", _File, _Line), true)
            : true)
        : false);   
    • 对于这种错误,我们一定要注意。cmp()函数实质是判断两个元素在何种状况下交换,交换相当于我们在冒泡排序和选择排序中熟悉的swap()函数,当cmp()返回1时执行swap(),返回0时不执行。

    • 而在sort排序时,一定要注意,函数要求对于调用的两个参数交换位置时不能得到相同的true的结果。详细参见:https://zhidao.baidu.com/question/543126728.html

    • 所以:

    bool cmp(vector<int> &a, vector<int> &b)  // 排序规则
    {
        int len = min(a.size(), b.size());
        for (int i = 0; i < len; i++)
        {
            if (a[i] == b[i])continue;
            else return a[i] > b[i];
        }
        return 0;    // 此处必须返回0
    }

    上述代码若返回1,则会报错,因为在两个vector相同的情况下,必定会交换位置,无论是a在前或者是b在前,都会得到true这个结果。

代码学习
  • 养成ac题后查看他人代码好习惯,baidu的第一位的又是一个大神,此题仅用了45行。
  • 在考虑输出路径这个问题时,选择了先对儿子结点进行从大到小排序,这样先搜索到的结果也一定是从大到小的。因此不用存储路径直接在叶节点输出即可。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int target;
struct NODE {
    int w;
    vector<int> child;
};
vector<NODE> v;
vector<int> path;
void dfs(int index, int nodeNum, int sum) {
    if(sum > target) return ;
    if(sum == target) {
        if(v[index].child.size() != 0) return;
        for(int i = 0; i < nodeNum; i++)
            printf("%d%c", v[path[i]].w, i != nodeNum - 1 ? ' ' : '\n');
        return ;
    }
    for(int i = 0; i < v[index].child.size(); i++) {
        int node = v[index].child[i];
        path[nodeNum] = node;
        dfs(node, nodeNum + 1, sum + v[node].w);
    }

}
int cmp1(int a, int b) {
    return v[a].w > v[b].w;
}
int main() {
    int n, m, node, k;
    scanf("%d %d %d", &n, &m, &target);
    v.resize(n), path.resize(n);
    for(int i = 0; i < n; i++)
        scanf("%d", &v[i].w);
    for(int i = 0; i < m; i++) {
        scanf("%d %d", &node, &k);
        v[node].child.resize(k);
        for(int j = 0; j < k; j++)
            scanf("%d", &v[node].child[j]);
        sort(v[node].child.begin(), v[node].child.end(), cmp1);
    }
    dfs(0, 1, v[0].w);
    return 0;
}

参考链接:https://blog.csdn.net/liuchuo/article/details/52258046

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值