蓝桥杯 历届试题 网络寻路(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.走过的点不能当终点,也就是说终点不能和路径中间的两个点一样

深搜合法路径计数就好

*/
原文地址:https://www.cnblogs.com/yinbiao/p/10066643.html