NOIP2014寻找道路

我看很多大佬都用的是bfs,我今天来发一篇dfs的题解。

但是很显然这道题dfs更好理解(自卖自夸)

很显然这道题中不是所有的边都能跑的,所以找到那些边可以走才是这道题的关键,剩下的就是一个最短路的板了,那么怎么找呢?

首先我们在建正图的时候统计每个点的出度,然后在建反图。 我们用一个cnt[]数组来存在跑反图的时候每个点能到达的次数,而且还要用一个vis[]数组来标记每个点只能跑一次。

很显然我们在跑完dfs后一个for循环遍历每个点看他的cnt[]值是不是大于等于他的出度,如果是这个点就可以跑,反之就不行。

剩下的就是一个dij的板了

话不多说直接上代码

原题链接:P2296 [NOIP2014 提高组] 寻找道路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
priority_queue<pair<int ,int> > p;
struct node {
    int f,t,nex;
}rt[200010],rt1[200010];
int head[200010];
int cnt;
int head1[200010];
int cnt1;
int vis[200010];
int qaq[200010];
int chudu[200010];
int vis1[200010];
int val[200010];
void add(int x,int y) {
    cnt ++;
    rt[cnt].f = x;
    rt[cnt].t = y;
    rt[cnt].nex = head[x];
    head[x] = cnt;
}
void add1(int x,int y) {
    cnt1 ++;
    rt1[cnt1].f = x;
    rt1[cnt1].t = y;
    rt1[cnt1].nex = head1[x];
    head1[x] = cnt1;
}
void dfs(int x) {
    if(!vis[x]) {
        vis[x] = 1;
        qaq[x] ++;
        for (int i = head1[x]; i  ; i = rt1[i].nex) {
            dfs(rt1[i].t);
        }
    }
    else {
        qaq[x] ++;
    }
}
int main() {
    int a,b;
    cin>>a>>b;
    for (int i = 1; i <= b; ++i) {
        int x,y;
        cin>>x>>y;
        chudu[x] ++;
        add(x,y);
        add1(y,x);
    }
    int f,t;
    cin>>f>>t;
    dfs(t);
    memset(val,0x7f, sizeof(val));
    val[f] = 0;
    p.push(make_pair(0,f));
    for (int j = 1; j <= a; ++j) {
        if(chudu[j] <= qaq[j]) {
            vis1[j] = 1;
        }
    }
    while (!p.empty()) {
        int faq = p.top().second;
        p.pop();
        for (int i = head[faq]; i  ; i = rt[i].nex) {
            if(vis1[rt[i].t]) {
                if(val[rt[i].t] > val[faq] + 1) {
                    val[rt[i].t] = val[faq] + 1;
                    p.push(make_pair(-val[rt[i].t],rt[i].t));
                }
            }
        }
    }
    if(val[t] == 0x7f7f7f7f) {
        cout<<-1;
    }
    else {
        cout<<val[t];
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值