历届试题 网络寻路

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

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

如下图所示的网络。



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

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

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

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

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

输出格式
输出一个整数,表示满足要求的路径条数。
样例输入1
3 3
1 2
2 3
1 3
样例输出1
6
样例输入2
4 4
1 2
2 3
3 1
1 4
样例输出2
10

这是一道看起来十分简单的题目。

只要进行深搜就可以了,可是却让我发现了我之前一直没发现的自己编程上面常常犯的错误。就是想当然,不分实际情况,例如

在深搜回溯的时候 我一般想当然 在DFS之前vis=1在这之后vis=0;然而这道题目却告诉我不能随便改变DFS的初始状态

比如说下面的代码 我怎么也想不到会错
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>

using namespace std;
const int maxn=10100;
int n,m;
int u,v;
vector<int>G[maxn];
int vis[maxn]={0};
int ans=0;
vector<int>path;
void dfs(int s,int x,int in){

if(in==3){ans++;
for(int i=0;i<path.size();i++)
cout<<path[i]<<" ";
cout<<endl;

return;}
else{
for(int i=0;i<G[x].size();i++)
{int v=G[x][i];

if(vis[v]==0||(in==2&&v==s))
{
vis[v]=1;//错就错在这里啊
path.push_back(v);
    dfs(s,v,in+1);
    path.pop_back();
vis[v]=0;//这里如果第四个结点放的是和第一个结点一样数,vis就把这个结点的状态变了 导致下一轮的时候错了,可以把v 改成x

    }

}



} }


int main()
{
    freopen("d://jin.txt","r",stdin);

    cin>>n>>m;
  while(m--){
  cin>>u>>v;
  G[u].push_back(v);
  G[v].push_back(u);

  }

  for(int i=1;i<=n;i++){
vis[i]=1;
path.push_back(i);
  dfs(i,i,0);
  path.pop_back();
  vis[i]=0;
  }

  cout<<ans;


    return 0;
}
再比如说下面的代码 导致的就是比答案少了
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>

using namespace std;
const int maxn=10100;
int n,m;
int u,v;
vector<int>G[maxn];
int vis[maxn]={0};
int ans=0;
vector<int>path;
void dfs(int s,int x,int in){
vis[x]=1;//原本以为在dfs外面改变vis和里面是一样的,没想到啊
if(in==3){ans++;
for(int i=0;i<path.size();i++)
cout<<path[i]<<" ";
cout<<endl;

return;}//错在这里 提前return了状态都没变回来啊
else{
for(int i=0;i<G[x].size();i++)
{int v=G[x][i];

if(vis[v]==0||(in==2&&v==s))
{

path.push_back(v);
    dfs(s,v,in+1);
    path.pop_back();


    }

}



} vis[x]=0;}


int main()
{
    freopen("d://jin.txt","r",stdin);

    cin>>n>>m;
  while(m--){
  cin>>u>>v;
  G[u].push_back(v);
  G[v].push_back(u);

  }

  for(int i=1;i<=n;i++){

path.push_back(i);
  dfs(i,i,0);
  path.pop_back();//还是应该在这种地方先搞vis 因为这也是在一个循环里面的

  }

  cout<<ans;


    return 0;
}

下面是一种正确的方法

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>

using namespace std;
const int maxn=10100;
int n,m;
int u,v;
vector<int>G[maxn];
int vis[maxn]={0};
int ans=0;
vector<int>path;
void dfs(int s,int x,int in){

if(in==3){ans++;
for(int i=0;i<path.size();i++)
cout<<path[i]<<" ";
cout<<endl;

return;}
else{
for(int i=0;i<G[x].size();i++)
{int v=G[x][i];

if(vis[v]==0||(in==2&&v==s))
{
if(v!=s)vis[v]=1;
path.push_back(v);
    dfs(s,v,in+1);
    path.pop_back();
if(v!=s)vis[v]=0;

    }

}



} }


int main()
{
    freopen("d://jin.txt","r",stdin);

    cin>>n>>m;
  while(m--){
  cin>>u>>v;
  G[u].push_back(v);
  G[v].push_back(u);

  }

  for(int i=1;i<=n;i++){
vis[i]=1;
path.push_back(i);
  dfs(i,i,0);
  path.pop_back();
vis[i]=0;
  }

  cout<<ans;


    return 0;
}


所谓回溯,就是回到初始的状态






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值