題目鏈接: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);
}