在输入过程中对于一条边的两个点 x , y x,y x,y,从 x x x 做 B F S BFS BFS,记录每一个点到 x x x 的最短路程 d i s x dis_x disx。显然,最后 d i s y + 1 dis_y+1 disy+1 就是经过 x x x 的当前最小环长度。
在这个过程中同时求方案数。
令
f
x
=
1
f_x=1
fx=1;
当前遍历到点
u
u
u,先对它的所有邻接点
n
x
t
nxt
nxt 更新
d
i
s
dis
dis;(因为走的路径不是最短路,方案是无效的)
如果
d
i
s
n
x
t
=
d
i
s
u
+
1
dis_{nxt}=dis_u+1
disnxt=disu+1,则
f
n
x
t
←
f
n
x
t
+
f
x
f_{nxt}\gets f_{nxt}+f_x
fnxt←fnxt+fx。(走了最短路径)
B
F
S
BFS
BFS 做完后,
f
y
f_y
fy 就是经过
x
x
x 的最小环个数,对每个
f
y
f_y
fy 求和就是答案。
对于上面的一个过程,可以简单理解成:把图转换为一个 D A G DAG DAG(去掉了 d i s dis dis 值不连续的边),在上面做拓扑排序,求了方案数。
如果
d
i
s
y
+
1
<
n
u
m
dis_y+1
#include
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,num=1e9,dis[3001],f[3001],ans;
int head[3001],nxt[12001],to[12001],cnt;
vector<int> v;
void add(int u,int v)
{
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void bfs(int st)
{
queue<int> q;
memset(dis,0x3f,sizeof(dis));
memset(f,0,sizeof(f));
dis[st]=0;
f[st]=1;
q.push(st);
while(q.size()){
int k=q.front();
q.pop();
for(int i=head[k];i;i=nxt[i]){
if(dis[to[i]]>dis[k]+1){
q.push(to[i]);
dis[to[i]]=dis[k]+1;
}
if(dis[to[i]]==dis[k]+1){
f[to[i]]+=f[k];
}
}
}
}
int main()
{
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y);
bfs(x);
if(dis[y]<num) num=dis[y],ans=0;
if(dis[y]==num) ans+=f[y];
add(x,y),add(y,x);
}
cout<<ans;
}