历届试题 网络寻路

来源:互联网 发布:淘宝活动策划方案 编辑:程序博客网 时间:2024/06/09 16:24

问题描述
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;}


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






原创粉丝点击