当前位置 博文首页 > 文章内容

    P2296 寻找道路

    作者: 栏目:未分类 时间:2020-06-24 14:48:17

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    看到题目,直接莽了一个Dijkstra最短路,然后样例直接输出2,心态爆炸。回去看题,发现有一个 路径上的所有点的出边所指向的点都直接或间接与终点连通,说明这道题我们需要加一些特殊的处理

    对于以上这一张图,我们直接跑最短路会是 1->2->6 答案是2,但是因为题意,我们不能走2这个点,因为2的节点3不与6连通,所以我们只能走 1->4->5->6 答案是3。那我们怎么处理这种情况呢,我们可以反向建边,然后从终点跑,能跑的地方就先用一个ok数组赋值为true

    这样之后还没有结束,我们还需要进行一次check操作,如果你的儿子节点跑不到终点,那么你也跑不到,如图,3到达不了6,那么2我们也不能走,在这里我们可以再开一个数组记录,然后跑一遍最短路就可以了

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=1e6+50;
    int n,m;
    struct node{
    	int net,to,w;
    }e[2*MAXN];
    int head[2*MAXN],tot;
    void add(int u,int v,int w){
    	e[++tot].net=head[u];
    	e[tot].to=v;
    	e[tot].w=w;
    	head[u]=tot;
    }
    int d[2*MAXN];
    bool v[2*MAXN];
    bool ok[2*MAXN];
    bool en[2*MAXN];
    void dfs(int s){
    	ok[s-n]=1; //走得到,说明可以走 
    	int i;
    	for(i=head[s];i;i=e[i].net)
    	if(!ok[e[i].to-n])dfs(e[i].to); //继续搜 
    }
    void check(int s){
    	int i;
    	if(ok[s]==false) en[s]=false; //走不到,说明肯定是false 
    	else 
    	for(i=head[s];i;i=e[i].net){
    		if(ok[e[i].to]==false){ //如果儿子是false,父亲肯定也是false 
    			en[s]=false;
    			break;
    		}
    	}
    }
    int s,t;
    void spfa(int s){
    	int i,x,y,z;
    	queue<int> q;
    	for(i=1;i<=n;i++) d[i]=20050305;
    	q.push(s);
    	d[s]=0;
    	v[s]=true;
    	while(!q.empty()){
    		x=q.front();
    		q.pop();
    		for(i=head[x];i;i=e[i].net){
    			y=e[i].to,z=e[i].w;
    			if(d[y]>d[x]+z&&en[y]==true){ //这个点可以用才更新最短路 
    				d[y]=d[x]+z;
    				if(v[y]==false){
    					v[y]=true;
    					q.push(y);
    				}
    			}
    		}
    		v[s]=false;
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	int i;
    	for(i=1;i<=m;i++){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		add(u,v,1);
    		add(v+n,u+n,1); //开个两倍反向建边 
    	}
    	scanf("%d%d",&s,&t);
    	dfs(t+n); //处理ok数组(不能与重点连通的点) 
    	for(i=1;i<=n;i++) en[i]=true; //初始化 
    	for(i=1;i<=n;i++) check(i); //再检查一次,把不能走的点标记 
    	spfa(s); //跑最短路 
    	if(d[t]!=20050305) cout<<d[t];
    	else cout<<-1;
    	return 0;
    }