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;
}