题目链接:https://ac.nowcoder.com/acm/contest/3566/E
题目大意:
给定一个无向图,初始时无向图内的任意两点均有若干条路径,现在你可以加一条边,使得下一次随机删除一条边时,删除的边让某两个城市变成无法连接的概率最小,求最小概率。
思路:
一眼就可以看出,如果删除的是桥,那么就会形成两个城市无法连接的情况。
所以我加边的时候就需要尽可能地让一些桥变成不是桥的路径。
怎么做呢?很明显,如果是一条链,链上的边都是桥,而我只需要将链首尾相连,就可以使得这条链上的桥都不再是桥。
而且我们注意到,Tarjan边双联通缩点之后,原图就变成了一颗树,树上的边都是桥,所以我们只需要在树上找到最长的链,将这条链上的边都变成不是桥的路径,这样我们就可以去除最多的桥,也是最优的策略了。
综上,先缩点建树,再求一遍树的直径,答案就出来了。
#include<bits/stdc++.h>
#include<vector>
#include<stack>
#define int long long
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int mod=1e9+7;
typedef long long LL;
bool in[maxn]; int belong[maxn]; int bct; int Time; int dfn[maxn]; int low[maxn];
stack<int> s;
vector<int> e[maxn],G[maxn];
int n,m,len,id;
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++Time;
s.push(u);
in[u]=true;
int sz=e[u].size();
bool tag=false;
for(int i=0;i<sz;i++)
{
int v=e[u][i];
if(v==fa&&!tag)
{
tag=true;
continue;
}
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(in[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
int v;
++bct;
do{
v=s.top(); s.pop();
belong[v]=bct;
in[v]=false;
}while(v!=u);
}
}
void tarjan_init()
{
bct=Time=0;
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i);
for(int u=1;u<=n;u++)
{
int sz=e[u].size();
for(int j=0;j<sz;j++)
{
int v=e[u][j];
if(belong[u]==belong[v]) continue;
G[belong[u]].push_back(belong[v]);
}
}
}
void dfs(int u,int fa,int step)
{
if(step>len) { len=step; id=u; }
int sz=G[u].size();
for(int i=0;i<sz;i++)
{
int v=G[u][i];
if(v==fa) continue;
dfs(v,u,step+1);
}
}
//扩展GCD
ll ex_gcd(ll a,ll b,ll &x,ll &y){
if(b==0){x = 1ll;y = 0ll;return a;}
ll g = ex_gcd(b,a%b,x,y);
ll temp = x;
x = y;
y = temp - a/b*y;
return g;
}
//扩展欧几里得的另一种写法
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
//求解ax+by=gcd(a,b)的一组解
if(!b){
d=a,x=1ll,y=0ll;
}
else{
ex_gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
//逆元
ll inv(ll a,int mod){
ll X,Y;
ll g = ex_gcd(a,mod,X,Y);
if(g!=1)return -1;
return (X%mod + mod)%mod;
}
signed main(void)
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%lld%lld",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
tarjan_init();
len=0;
dfs(1,0,0);
len=0;
dfs(id,0,0);
int ans=inv(m+1,mod)*(bct-1-len)%mod;
printf("%lld\n",ans);
}