蓝桥杯2013年国赛A组——网络寻路(DFS和中转边巧解)

蓝桥杯2013年国赛A组——网络寻路

1.题目描述
在这里插入图片描述
2.输入输出
在这里插入图片描述
3.样例输入和输出
在这里插入图片描述
4.题目分析
1.首先明确,题目中的目的地有两种,一种是回到原点,一种是到达没有到达的地方
2.在路径中经过的点不能有重复的点
3.有题目可知,4 1 2 3和3 2 1 4是两条不同的路径
4.给出题目中样例的图示
在这里插入图片描述
5.解题思路
思路一:DFS暴力求解
1.使用vis[]数组记录经过的点;

2.使用DFS寻找可能的路径,因为路径的长度是4,那么当寻找路径上的前3个点的时候,如果可以从前一个点走到当前的点,并且当前的点没有走过,那么将当前的点设置为路径当中的点。

3.寻找路径第四个点的时候,有两种可能的情况,一种是可以到达的第四个点是之前没有走过的点,方案数量加一,另外一的情况是可以到达的第四个点是第一个点(走回到了起点),方案数量加一。

4.建图时采用邻接表而不是邻接矩阵,防止超时
代码如下

#include<bits/stdc++.h>
using namespace std;
int M,N,u,v,ans;
#define maxn 10010
vector<int>G[maxn];
bool used[maxn];
 
//u表示上一个顶点,dep表示当前寻找第dep+1个结点,s表示起点; 
void DFS(int u,int dep,int s){
    if(dep==3){ 
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!used[v] || v==s) ans++; 
        }
        return ;
    }
    else{
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!used[v]){
                used[v]=true;
                DFS(v,dep+1,s);
                used[v]=false;
            }
        }
    }
    return ;
}
 
int main(void){
    cin>>N>>M;
    while(M--){
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
     
    memset(used,0,sizeof used);
    for(int i=1;i<=N;i++){
        used[i]=true; 
        DFS(i,1,i);
        used[i]=false; 
    }
    cout<<ans;
    return 0;
}

思路二:利用中转边

这个方法是在网上众多DFS解法中让我眼前一亮的另一种解法,非常巧妙。
题目要求转发两次,实际上任何符合题意的解都会产生三条边,那么我们就抓住中间那条边(把它称作中转边)。中转边的两个顶点edge(u,v),若要符合题意,则这两个顶点除了连接中转边外,还需要其他边来形成不同的组合。那么由这条中转边构成符合题意的解为:
(u的度数-1)*(v的度数-1)
接着再遍历所有的中转边每一个都按照这个公式去算得出ans
最后由于是无向图,可以反向同行,所以最后ans*2

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 10005
 
struct Road {
    int u,v;
}road[100005];
int n,m;
ll in[N];
 
int main()
{
    int i,j,cas=0;
        cin>>n>>m;
 
        memset(in,0,sizeof(in));
        for(i=1;i<=m;i++) {
            cin>>road[i].u>>road[i].v;
            in[road[i].u]++; in[road[i].v]++;
        }
 
        ll ret=0;
        for(i=1;i<=m;i++) {
            int u=road[i].u;
            int v=road[i].v;
            ret+=(in[u]-1)*(in[v]-1)*2;
        }
 
        cout<<ret;
    
    return 0;
}
 

算法复杂度O(m)

6.总结:
DFS更直接更暴力更容易去想,但是写起来代码有点长,而且需要对DFS非常熟悉才行,并且存在超时的可能性

利用中转边更加巧妙,但是真的很难想到,想到之后就非常简答,时间复杂度低并且代码简单易写

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chase__young

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值