zoukankan      html  css  js  c++  java
  • 【NOIP2014】选择道路

    这题值得记录。

    题目大意

    在有向图 GGG 中,每条边的长度均为 1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

    1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
    2. 在满足条件  1 的情况下使路径最短。

    注意:图 GGG 中可能存在重边和自环,题目保证终点没有出边。

    请你输出符合条件的路径的长度。

    ***具体题面请看https://www.luogu.org/problemnew/show/P2296

    题解

    我的思路是存图的时候另开数组反向存边,然后在反向存边的图中用DFS将从终点出发能走到的点标记为1,然后一遍For循环,枚举标记为1的点的出边所到的点,如果出边所到的点中有标记为0的点,就说明当前点是不符合题目要求1的。

    注意:但是我们在这里不能直接删去这个点,如果删去的话,会改变图的形态从而删去更多的点。(我就这里改了一个中午...)

    所以我们再开个数组记录哪些点要删去,后统一删去即可,最后跑一遍SPFA。

    错误删点方式:

       for(int i=1;i<=n;i++)
       {
            if(flag[i])
            for(int j=head[i];j;j=edge[j].next){
            int too=edge[j].to;
            if(!flag[too]){
                flag[i]=0;
                break;
                }
            }
       }

    正确删点方式:

       for(int i=1;i<=n;i++)
       {
            if(flag[i]&&i!=t)
            for(int j=head[i];j;j=edge[j].next){
            int too=edge[j].to;
            if(!flag[too]){
                judge[i]=1;
                break;
                }
            }
       }
       for(int i=1;i<=n;i++){
           if(judge[i])
           flag[i]=0;
       }

    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #define ll long long int
    using namespace std;
    int judge[10008];
    int n,m,num,cnt,q[50005],pd[10005],head[10005],HEAD[10005],NUM,s,t,flag[10005],ans[10005];
    struct Edge{
        int next,dis,to;
    }edge[200005];
    struct EDGE{
        int next,dis,to;
    }road[200005];
    void add(int u,int v)
    {
        edge[++num].next=head[u];
        edge[num].dis=1;
        edge[num].to=v;
        head[u]=num;
    }
    void ADD(int u,int v){
        road[++NUM].next=HEAD[u];
        road[NUM].dis=1;
        road[NUM].to=v;
        HEAD[u]=NUM;
    }
    void dfs(int pos)
    {
        for(int i=HEAD[pos];i;i=road[i].next){
            int too=road[i].to;
            if(!flag[too]&&too!=pos){
                flag[too]=1;
                dfs(too);
            }
        }
    }
    void spfa()
    {
        ans[s]=0;
        q[1]=s;
        int l=0,r=1;
        while(l<r)
        {
            l++;
            int now=q[l];
            pd[now]=0;
            for(int i=head[now];i;i=edge[i].next){
                int too=edge[i].to;
                if(!flag[too])continue;
                if(ans[too]>ans[now]+edge[i].dis){
                ans[too]=ans[now]+edge[i].dis;
                if(!pd[too]){
                    r++;
                    pd[too]=1;
                    q[r]=too;
                }
                }
            }
        }
    }
    int main()
    {
        memset(flag,0,sizeof(flag));
        memset(pd,0,sizeof(pd));
        memset(ans,0x3f3f3f3f,sizeof(ans));
       scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
           int u,v;
           scanf("%d%d",&u,&v);
           add(u,v);
           ADD(v,u);
       }
       scanf("%d%d",&s,&t);
       flag[t]=1;
       dfs(t);
       if(!flag[s]){
           printf("-1");
           return 0;
       }
       for(int i=head[s];i;i=edge[i].next)
       {
           if(!flag[edge[i].to]){
               printf("-1");
               return 0;
           }
       }
       for(int i=1;i<=n;i++)
       {
            if(flag[i]&&i!=t)
            for(int j=head[i];j;j=edge[j].next){
            int too=edge[j].to;
            if(!flag[too]){
                judge[i]=1;
                break;
                }
            }
       }
       for(int i=1;i<=n;i++){
           if(judge[i])
           flag[i]=0;
       }
       spfa();
       if(ans[t]==0x3f3f3f3f)
       printf("-1");
       else
       printf("%d",ans[t]);
       return 0;
    }

    我的代码还是比较长的,网上还有一些BFS+DFS的做法代码贼短...

  • 相关阅读:
    python面试题总结(1)
    python数据结构与算法之算法和算法分析
    python数据结构与算法之问题求解实例
    python数据结构与算法之问题求解
    导航栏挡住View
    coredata
    SVN
    mac 上用到的数据库软件
    开博感言
    九 、循环队列的java实现
  • 原文地址:https://www.cnblogs.com/sky-zxz/p/9390527.html
Copyright © 2011-2022 走看看