X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。
源地址和目标地址可以相同,但中间节点必须不同。
如图 11 所示的网络。
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)。
输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。
输出格式
输出一个整数,表示满足要求的路径条数。
输入输出样例
输入
3 3
1 2
2 3
1 3
输出
6
输入
4 4
1 2
2 3
3 1
1 4
输出
10
说明/提示
时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛
解法一(暴搜)
cpp
#include<iostream>
#include<vector>
using namespace std;
int n,m,ans,f;
vector<int>e[100005];
bool vis[10005];
void dfs(int a,int b){
if(b==4)ans++; //到达第四个节点,方案数加一
else{
for(int i=0;i<e[a].size();i++){ //遍历a节点的所有子节点
int v=e[a][i];
if(!vis[v]){ //如果该点还未使用
vis[v]=1;
dfs(v,b+1);
vis[v]=0; //回溯
}else if(b==3&&v==f)dfs(v,b+1); //如果已经走了两步了,下一个为置又回到原点也是一种可行方案
}
}
}
int main(){
cin>>n>>m;
int x,y,k=m;
while(k--){ //因为是双向传输,所以要存两个节点
cin>>x>>y;
e[x].push_back(y);
e[y].push_back(x);
}
for(int i=1;i<=n;i++){ //从第一个节点开始遍历,依次枚举所有节点
vis[i]=1;
f=i;
dfs(f,1);
vis[i]=0;
}
cout<<ans<<endl;
return 0;
}
解法二(中转边)借鉴dalao的
一条边的两个节点如果还连有其它边,就两边相乘,因为是双向的就再乘以2
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
struct Node{
int u,v;
}h[N];
int n,m;
LL a[10005];
int main(){
cin>>n>>m;
memset(a,0,sizeof a);
for(int i=1;i<=m;i++){
cin>>h[i].u>>h[i].v;
a[h[i].u]++;
a[h[i].v]++;
}
LL ans=0;
for(int i=1;i<=m;i++){
int u=h[i].u;
int v=h[i].v;
ans+=(a[u]-1)*(a[v]-1)*2;
}
cout<<ans<<endl;
return 0;
}