CSU1092-Barricade-最短路/Dijkstra

D: Barricade

Description

GBQC国一共有N个城市,标号分别为1, 2, …, N。N个城市间一共有M条单向通行的道路。

不幸的是,GBQC国的城市1连续暴雨,使得整个城市淹没在汪洋洪水中,于是GBQC国领导人小明决定让城市1的居民暂时移居到城市N,于是一场浩浩荡荡的搬迁运动开始了。

但还有一个问题需要解决,居民从城市1出发,如果走到某个城市时面对多条道路,那么城市1的居民就不知道该往哪个方向走了。

为了解决上述问题,GBQC国领导人决定在一些道路的入口处设置“禁止通行”的路障,以确保城市1的居民从城市1出发,途径每个城市时,都有且仅有一条路可供选择,这样城市1的居民就能顺利搬迁到城市N了。

​ 现在GBQC国领导人想知道最少需要设置几个路障呢?

Input

输入包含多组测试数据。

对于每组测试数据,第一行包含两个整数N(2<=N<=10^4), M(0<=M<=10^5),其中N、M的含义同上。接下来一共有M行,每行有三个整数x(1<=x<=N)、y(1<=y<=N),表示GBQC国有一条由城市x进入通向城市y的单向道路。

Output

对于每组测试数据,用一行输出一个整数表示最少需要设置几个路障。如果没办法从城市1出发走到城市N,则输出“-1”(不包括引号)。

Sample Input

3 4
1 1
1 2
1 3
1 3

3 2
1 3
3 2

2 0

Sample Output

3
0
-1

Hint

​ 由于数据量较大,推荐使用scanf和printf。

思路:这个题可以这样考虑,最小的路障就可以视为是一个权值的问题,而Dijkstra算法又不会重复走某个点,则每条边的权值就为起始点的出度-1,故先读入图,第一遍记录每个点的出度,第二遍利用第一遍得到的出度建图,跑一边Dijkstra,判断dis[n]是有还是无按要求输出。
我用了紫书的模板

#include <bits/stdc++.h>
#define N 101000
#define INF 0x3f3f3f3f
#define LL long long
#define mem(a,n) memset(a,n,sizeof(a))
#define fread freopen("in.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)
using namespace std;
struct Edge{
    int from,to,dist;
    Edge(int u,int v,int d):from(u),to(v),dist(d){};
};
struct HeapNode{
    int d,u;
    bool operator<(const HeapNode &a) const {
        return d>a.d;
    }
};
struct Dijkstra{
    int n,m;
    vector<Edge> edges;
    vector<int> G[N];
    bool vis[N];//是否永久标号 
    int d[N];//松弛操作 
    int p[N];//最短路中的上一条弧

    void init(int n) {
        this->n=n;
        for(int i=0;i<n;++i){
            G[i].clear();
        }
        edges.clear();
    }

    void AddEdge(int from,int to,int dist){
        edges.push_back(Edge(from,to,dist));
        m=edges.size();
        G[from].push_back(m-1);
    }

    void dijkstra(int s){
        priority_queue<HeapNode> q;
        for(int i=0;i<n;++i){
            d[i]=INF;
        }
        d[s]=0;
        mem(vis,0);
        q.push((HeapNode){0,s});
        while(!q.empty()){
            HeapNode x=q.top();
            q.pop();
            int u=x.u;
            if(vis[u]){
                continue;
            }
            vis[u]=true;
            for(int i=0;i<G[u].size();++i){
                Edge &e=edges[G[u][i]];
                if(d[e.to]>d[u]+e.dist){
                    d[e.to]=d[u]+e.dist;
                    p[e.to]=G[u][i];
                    q.push((HeapNode){d[e.to],e.to});
                }
            }
        }
    }
};
int outdeg[N],path[N][2];
Dijkstra Dick;
int main()
{
    ios::sync_with_stdio(false);
    int n,d,c1,c2,cnt;
    while(cin>>n>>d){
        Dick.init(n+1);
        mem(outdeg,0);
        for(int i=0;i<d;++i){
            cin>>path[i][0]>>path[i][1];
            ++outdeg[path[i][0]];
        }
        for(int i=0;i<d;++i){
            Dick.AddEdge(path[i][0],path[i][1],outdeg[path[i][0]]-1);
        }
        Dick.dijkstra(1);
        cout<<(Dick.d[n]==INF?-1:Dick.d[n])<<endl; 
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值