牛客练习赛 56 E
这道题其实并不难,为什么要写他呢? 因为被他坑了
题目:
给一个图,自己加上一条边后,问随机删去一条边后让图不连通的最小概率。
很明显缩点建图 然后 跑个树的直径
设直径为 d 缩点图上共 m 条边 原先图*** s 条边 答案就是 (m-d)/(s+1)
但是 只能过%95的样例 为什么??
有重边
好吧 我的板子有问题
那个Tra……的算法
无向图求缩点:我本来写的是防止回到他的上一个节点 x==fa continue;
但是这样的话如果这两个节点间有两条边 他就是一个强连通分量 就可以回到上一个节点所以板子改进一下。。。
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 2e5+5;
vector<int> vv[maxn];
int dfn[maxn];
int low[maxn];
int col[maxn];
int vis[maxn];
int pos;
stack<int> ss;
int cnt;
void dfs(int x,int fa)
{
// printf("%d\n",x);
dfn[x] = low[x] = ++ pos;
ss.push(x);
vis[x] = 1;
int f = 0;
for (int i = 0; i < vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
{
f++;
if(f == 1)
continue;
}
if(dfn[v] == 0)
{
dfs(v,x);
low[x] = min(low[x],low[v]);
}
else
low[x] = min(low[x],dfn[v]);
}
if(dfn[x] == low[x])
{
++cnt;
while(ss.top()!=x)
{
col[ss.top()] = cnt;
vis[ss.top()] = 0;
ss.pop();
}
col[x] = cnt;
vis[x] = 0;
ss.pop();
}
}
vector<int> sd[maxn];
int dep[maxn];
int root;
void dfs2(int x,int fa,int dp)
{
dep[x] = dp;
if(dep[x] >= dep[root])
{
root = x;
}
for (int i = 0; i< sd[x].size(); i ++ )
{
int v = sd[x][i];
if(v == fa)
continue;
dfs2(v,x,dp+1);
}
}
ll quick(ll a,ll b)
{
ll ans = 1;
while(b)
{
if(b & 1)
{
ans = ans * a % mod;
}
a = a*a%mod;
b >>= 1;
}
return ans%mod;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0; i < m; i ++ )
{
int x,y;
scanf("%d%d",&x,&y);
vv[x].push_back(y);
vv[y].push_back(x);
}
for (int i = 1; i <= n; i ++ )
{
if(dfn[i] == 0)
{
dfs(i,-1);
}
}
// for (int i= 1; i <= n; i ++ )
// {
// printf("%d ",col[i]);
// }
int s = 0;
for (int i = 1; i <= n; i ++ )
{
int x = col[i];
for (int j = 0 ;j < vv[i].size(); j ++ )
{
int y = col[vv[i][j]];
if(x == y)
continue;
sd[x].push_back(y);
s++;
}
}
// printf("%d\n",s);
s/=2;
root = 0;
dep[0] = 0;
dfs2(1,-1,1);
int x = root;
root = 0;
dep[0] = 0;
dfs2(x,-1,1);
s -= dep[root] - 1;
// printf("%d\n",s);
ll ans = 1ll * s * quick(1ll*m+1,mod-2) %mod;
printf("%lld\n",ans);
}