zoukankan      html  css  js  c++  java
  • 蓝桥杯 历届试题 网络寻路(dfs搜索合法路径计数)

    X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。

    源地址和目标地址可以相同,但中间节点必须不同。

    如下图所示的网络。


    1 -> 2 -> 3 -> 1 是允许的

    1 -> 2 -> 1 -> 2 或者 1 -> 2 -> 3 -> 2 都是非法的。

    Input

    输入数据的第一行为两个整数N M,分别表示节点个数和连接线路的条数(1<=N<=10000; 0<=M<=100000)。

    接下去有M行,每行为两个整数 u 和 v,表示节点u 和 v 联通(1<=u,v<=N , u!=v)。

    输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。

    Output

    输出一个整数,表示满足要求的路径条数。

    Sample Input

    样例输入1
    3 3
    1 2
    2 3
    1 3
    
    样例输入2
    4 4
    1 2
    2 3
    3 1
    1 4

    Sample Output

    样例输出1
    6
    
    样例输出2
    10

    Source

    蓝桥杯
     
    合法路径:
    1.最多走过4个结点
    2.终点可以和起点相同或者不同
    3.走过的点不能当终点,也就是说终点不能和路径中间的两个点一样
    深搜合法路径计数就好
     
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define INF 99999999
    #define me(a,x) memset(a,x,sizeof(a))
    int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
    int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
    int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
    int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};//i的阶乘
    LL getval()
    {
        LL ret(0);
        char c;
        while((c=getchar())==' '||c=='
    '||c=='
    ');
        ret=c-'0';
        while((c=getchar())!=' '&&c!='
    '&&c!='
    ')
            ret=ret*10+c-'0';
        return ret;
    }
    void out(int a)
    {
        if(a>9)
            out(a/10);
        putchar(a%10+'0');
    }
    int kt(int a[],int n)//康托展开
    {
        int ans=0;
        for(int i=1; i<=n; i++) //下标从1开始
        {
            int c=0;
            for(int j=i+1; j<=n; j++)
            {
                if(a[j]<a[i])
                    c++;
            }
            ans+=(c*fac[n-i]);
        }
        return ans+1;
    }
    
    #define max_v 10005
    vector<int> G[max_v];
    int vis[max_v];
    int ans;
    
    void dfs(int s,int cur,int step)//起点是s,当前点是cur,当前步数是step
    {
        if(step<=2)//步数小于2,继续深搜
        {
            for(int i=0;i<G[cur].size();i++)
            {
                int next=G[cur][i];//下一步要走的点
                if(vis[next]==0)//没有走过
                {
                    vis[next]=1;
                    dfs(s,next,step+1);
                    vis[next]=0;//回退
                }
            }
        }
        if(step==3)//步数等于3,只要可以找到合格的终点就好了,不用继续深搜
        {
            for(int i=0;i<G[cur].size();i++)
            {
                int f=G[cur][i];//终点
                if(vis[f]==0)//终点没有访问过
                    ans++;
                if(f==s)//终点和源点重合
                    ans++;
            }
        }
    }
    int main()
    {
        int n,m;
        scanf("%d %d",&n,&m);
        int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        me(vis,0);
        ans=0;
        for(int i=1;i<=n;i++)
        {
            vis[i]=1;
            dfs(i,i,1);//以起点是i,当前点是i,步数是1开始深搜
            vis[i]=0;//回退 状态回退是深搜的重要标志之一!!!
        }
        printf("%d
    ",ans);
    }
    /*
    合法路径:
    1.最多走过4个结点
    2.终点可以和起点相同或者不同
    3.走过的点不能当终点,也就是说终点不能和路径中间的两个点一样
    
    深搜合法路径计数就好
    
    */
  • 相关阅读:
    作业四 四则运算
    作业三
    作业二(3)
    作业二(2)
    作业二(1)
    作业一
    作业九
    每周更新学习进度表--第十一周
    每周更新学习进度表--第十周
    每周更新学习进度表--第九周
  • 原文地址:https://www.cnblogs.com/yinbiao/p/10066643.html
Copyright © 2011-2022 走看看