首页 > 试题广场 >

路径数组变为统计数组

[编程题]路径数组变为统计数组
  • 热度指数:607 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个路径统计数组paths,表示一张图。paths[i]==j代表城市i连向城市j,如果paths[i]==i,则表示i城市是首都,一张图里只会有一个首都且图中除首都指向自己之外不会有环。例如,paths=[9,1,4,9,0,4,8,9,0,1],代表的图如图9-14所示。
由数组表示的图可以知道,城市1是首都,所以距离为0,离首都距离为1的城市只有城市9,离首都距离为2的城市有城市0、3和7,离首都距离为3的城市有城市4和8,离首都距离为4的城市有城市2、5和6。所以距离为0的城市有1座,距离为1的城市有1座,距离为2的城市有3座,距离为3的城市有2座,距离为4的城市有3座。那么统计数组为nums=[1,1,3,2,3,0,0,0,0,0]
[要求]
时间复杂度为,额外空间复杂度为

输入描述:
第一行有一个整数N,表示节点个数。
接下来一行有N个整数表示paths。其中第i个整数表示第i-1个节点的祖先


输出描述:
输出N个整数表示nums。
示例1

输入

10
9 1 4 9 0 4 8 9 0 1

输出

1 1 3 2 3 0 0 0 0 0

备注:
保证输入合法。
#include <bits/stdc++.h>
using namespace std;

int n;
int dist(int *a, int *d, int k){
    if(d[k]>=0)
        return d[k];
    if(a[k]==k){
        d[k] = 0;
        return d[k];
    }
    d[k] = dist(a, d, a[k])+1;
    return d[k];
}

int main(){
    cin>>n;
    int a[n], d[n], r[n];
    memset(a, 0, sizeof(a));
    fill(d, d+n, -1);
    memset(r, 0, sizeof(r));
    for(int i=0;i<n;i++)
        cin>>a[i];
    for(int i=0;i<n;i++)
        dist(a, d, i);
    for(int i=0;i<n;i++)
        if(d[i]>=0)
            r[d[i]]++;
    for(int i=0;i<n;i++)
        cout<<r[i]<<" ";
    return 0;
}

发表于 2020-03-25 23:34:26 回复(0)
1、从左到右遍历paths,先遍历到位置0。 
 paths[0] == 9,首先令paths[0] == -1(这是为了标记起跳的城市),因为城市0指向城市9,所以跳到城市9. 
 跳到城市9之后,paths[9] == 1,说明下一个城市是1,因为城市9是由城市0跳过来的,所以先令paths[9] = 0,然后跳向城市1。 
 跳到城市1之后,paths[1] == 1,说明城市1是首都。现在开始往回跳,城市1是由城市9跳过来的,所以跳回城市9。 
 根据之前设置的paths[9] == 0,我们知道城市9是由城市0跳过来的,在回跳之前先设置paths[9] = -1,表示城市9到首都的距离为1,之后回跳到0。 
 根据之前的设置paths[0] == -1,我们知道城市0是起跳位置,所以不再回跳,令paths[0] == -2,表示到首都的距离为2。 
 以上在跳向首都的过程中,paths数组有一个路径反指的过程,这是为了保证找到首都之后,能够完全跳回来。在跳回来的过程中,设置好这一路所跳的城市即可。
2、对于其他位置,跳跃的过程同上,但是跳跃终止的条件可以不是跳到首都,当我们跳到下一个位置发现它的值是负数,说明这个位置已经计算出了到首都的距离,我们只要在这个基础上来设置距离即可。
3、首都我们单独处理即可,找到首都的位置然后将它的值设为0,表示距离为0。
 得到距离数组后,数组中的距离值都用负数表示。接下来我们根据距离数组来计算得到统计数组。该过程也是一个跳跃的过程。从左到右遍历数组,假设遍历到为i,paths[i] == -j,那么我们可以知道城市i距离首都的距离是j,先令paths[i] == 0,表示此位置不再代表距离,然后跳到位置j处,如果位置j处的值为负数-k,我们令paths[j] = 1,表示我们已经找到一个距离为j的城市(城市i)。然后根据k继续往下跳。如果位置j处的值为正数,说明该位置已经是距离为j的城市的数量统计,直接加1即可。
#include<bits/stdc++.h>
using namespace std;
int main() {
    int n,cap=0,count=0;
    cin>>n;
    vector<int>path(n);
    map<int, vector<int>> mp;
    for(int i=0;i<n;i++)
    {
        cin>>path[i];
        if(path[i]==i)
            cap=i;
        else
            mp[path[i]].push_back(i);
    }
    deque<int> result,first,second;
    first.push_back(cap);
    while (!first.empty()) 
    {
        int tmp=first.front();
        first.pop_front();
        for(int i=0;i<mp[tmp].size();i++)
        {
            second.push_back(mp[tmp][i]);
            count++;
        }
        if(!first.empty())
            continue;
        else
        {
            result.push_back(count);
            first = second;;
            second.clear();
            count = 0;
        }
    }
    result.push_front(1);
    while (result.size() > path.size()) 
        result.pop_back();
    while (result.size() < path.size()) 
        result.push_back(0);
    int length = path.size();
    path.clear();
    for (int i = 0; i < length; ++i)
        cout<<result[i]<<" ";
    return 0;
}

发表于 2019-09-03 20:23:51 回复(0)
从首都不断外延,相当于树木的层次遍历过程。
基于hash_map建立映射过程  即map<int,vector<int>> 建议一个节点的外延节点(注意和读取过程方向相反)

int main()
{
    int n;
    cin>>n;
    unordered_map<int,vector<int>> mp;  //map[k]=vec 表示从k城市出发的外延城市
    int index=-1;
    for(int i=0;i<n;i++)
    {
        int dest;
        cin>>dest;
        if(i==dest)
            index=i;
        else
            mp[dest].push_back(i);//也即 dest可以外延到i
        //那么存在i=>dest的路径
    }
    vector<int> ans(n,0);
    queue<int> q;
    q.push(index);
    int count=0;
    while(q.empty()==false)
    {
        ans[count]=q.size();//当前层的数量
        for(int i=0;i<ans[count];i++)
        {
            int num=q.front();
            q.pop();
            for(int k=0;k<mp[num].size();k++)
                q.push(mp[num][k]);//将num的外延节点加入
        }
        
        count++;

    }
    for(int i=0;i<n;i++)
        cout<<ans[i]<<" ";

}


编辑于 2020-11-27 01:31:43 回复(0)