【NHOI2018】跳伞登山赛

 

【题目描述】
某山区有高高低低的 n 个山峰,根据海拔高度的不同,这些山峰由低到高进行了 1 到 n 编号。有 m 条只能单向通行的羊肠小道连接这些山峰。现在,这里要举行一场跳伞登山赛,选手们伞降到某山峰后,再通过山间小道向属于自己的最高峰进军。
小明也参加了这次比赛,你能否告诉他,从任意一座山峰出发所能到达的最高峰编号是多少?
【输入数据】
输入共 m+1 行。
第 1 行为 2 个整数 n、m,用一个空格隔开,表示山峰总数和道路总数。
接下来 m 行,每行 2 个整数,用一个空格隔开,表示一条道路的起点和终点山峰编号。
【输出数据】
输出共 1 行,n 个整数,用一个空格隔开,表示每座山峰所能到达的最高峰的编号。
【样例输入】
4 3
1 2
2 4
4 3
【样例输出】
4 4 3 4
【数据范围】
60%的数据满足:1≤m,n≤10^3;
100%的数据满足:1≤m,n≤10^5。
【解题思路】
按照输入的数据反向建图,从最大往回走,给连通的每一个点作标志。
原理就是从大到小走,第一个走到的绝对是最优解,省去了大量的时间。
【参考程序】

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> edge[100005];
bool visit[100005];
int f[100005],n,m,s,e;
void dfs(int val,int sta)
{
    visit[sta]=true;
    for (int i=0;i<edge[sta].size();i++)
        if (!visit[edge[sta][i]])
        {
            f[edge[sta][i]]=val;//做标记
            dfs(val,edge[sta][i]);//继续走
        }
}
int main()
{
    //freopen("race.in","r",stdin);
    //freopen("race.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&s,&e);
        edge[e].push_back(s);
    }
    for (int i=1;i<=n;i++)
        f[i]=i;
    for (int i=n;i>=1;i--)
    {
        if (visit[i]) continue;
        dfs(f[i],i);
    }
    for (int i=1;i<=n;i++) printf("%d ",f[i]);
    return 0;
}
posted @ 2018-06-07 18:43  Nanjo  阅读(299)  评论(0编辑  收藏  举报