[NOIP2014]寻找道路
思路
首先要把一些不满足条件的点剔除掉,然后就是求最短路的事情了。
要找不满足条件的点,可以反向建边,然后从终点出发,标记每一个经过的点。那么剩下没有走过的点就可以去掉了。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=10005,maxm=200005;
int cant[maxn],vis[maxn],dis[maxn];
int n,m,s,t,e,u,v;
struct E{
int next,to;
}edge[maxm],edge2[maxm];
struct node{
int n,w;
};
bool operator<(const node a,const node b){
return a.w<b.w;
}
void read(int &data){
int flag=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') flag=-flag;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
data=flag*x;
}
priority_queue<node>pq;
int head[maxn],head2[maxn],cnt=0,cnt2=0;
inline void addedge(int from,int to){
edge[++cnt].next=head[from];
edge[cnt].to=to;
head[from]=cnt;
edge2[++cnt2].next=head2[to];
edge2[cnt2].to=from;
head2[to]=cnt2;
}
void dfs(int x){
vis[x]=1;
for(int i=head2[x];i;i=edge2[i].next){
int y=edge2[i].to;
if(!vis[y]){
dfs(y);
}
}
}
void dijistra(int s){
memset(dis,127/3,sizeof(dis));
if(cant[s]) return;
pq.push((node){s,0});
dis[s]=0;
while(!pq.empty()){
node fro=pq.top();
pq.pop();
if(dis[fro.n]!=fro.w) continue;
for(int i=head[fro.n];i;i=edge[i].next){
int y=edge[i].to;
if(cant[y]) continue;
if(dis[y]>dis[fro.n]+1){
dis[y]=dis[fro.n]+1;
pq.push((node){y,dis[y]});
}
}
}
}
int main(){
read(n);read(m);
for(int i=1;i<=m;i++){
read(u);read(v);
if(u==v)continue; //去重边
addedge(u,v); //建反向边
}
read(s);read(t);
dfs(t); //从终点出发,找出无法到达的点
for(int i=1;i<=n;i++)
if(!vis[i]) cant[i]=1;
for(int i=1;i<=n;i++){
if(!vis[i]) continue;
int flag=0;
for(int j=head[i];j;j=edge[j].next){
int y=edge[j].to;
if(!vis[y]){ //如果出点被剔除,那么该点也被剔除
flag=1;
break;
}
}
if(flag) cant[i]=1; //该数组存储最终剔除的结点
}
dijistra(s); //找最短路
if(dis[t]>1e6+7) cout<<-1<<endl;
else cout<<dis[t]<<endl;
return 0;
} 
京公网安备 11010502036488号