牛客练习赛56 E 图

牛客练习赛 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值