Codeforces Round #606 (Div. 1)B. Two Fairs(图论,组合数学)

文章描述了解决一个给定无向联通图的问题,计算从一个点到另一个点都必须经过两个特殊点a和b的路径对数。通过深度优先搜索(DFS)分别标记从a到b和b到其他点的路径,然后使用乘法原理得出答案。
摘要由CSDN通过智能技术生成

原题链接:B. Two Fairs
题目大意
给出一张有 n 个结点、m 条边的无向联通图,同时给出a,b两个特殊点,询问图上有多少对点满足从一个点到另一个点都必须经过这两个重要点,即求出任意一条从u到v的路径都经过a和b的二元组 (u,v) 的对数
数据范围:1≤t≤4⋅104,4≤n≤2⋅105 , n−1≤m≤5⋅105, 1≤a,b≤n, a≠b,1≤ui,vi≤n , ui≠vi
测试中所有输入数据的n之和不超过2⋅105.测试中所有输入数据的m值总和不超过5⋅105
解题思路:
首先,给出一个图,我们可以先思考哪些点u是从u走到b必须经过点a的,
在这里插入图片描述
显然图中标红的点走到b点是必须经过a点的,那么如何找到这些点呢?
我们可以从b点开始进行dfs,碰到a点就返回,剩下未被标记的点就是走到b点是必须经过a点的点

void dfsb(int x)
{
	if(visb[x]||x==a)return;
	visb[x]=1;
	nb++;
	for (int i=0;i<ed[x].size();i++)
	{
		int p=ed[x][i];
		if (visb[p]) continue;
		dfsb(p);
	}
}

标记结果如下图:

在这里插入图片描述
假设被标记的点的数量为na,那么未被标记的点的数量为n-na,注意a点是不能选中的,所以满足要求的点为n-na-1
对点B分析时用相同的操作,可得到满足要求的点数量为n-nb-1,最后用乘法原理即可得出答案

cout<<(n-na-1)*(n-nb-1)<<'\n';

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int visa[200005],visb[200005];
vector<int> ed[600005]; 
int n,m,a,b;
int na,nb; 
void dfsa(int x)
{
	if(visa[x]||x==b)return;
	visa[x]=1;
	na++;
	for (int i=0;i<ed[x].size();i++)
	{
		int p=ed[x][i];
		if (visa[p]) continue;
		dfsa(p);
	}
}
void dfsb(int x)
{
	if(visb[x]||x==a)return;
	visb[x]=1;
	nb++;
	for (int i=0;i<ed[x].size();i++)
	{
		int p=ed[x][i];
		if (visb[p]) continue;
		dfsb(p);
	}
}
void solve(){
	cin>>n>>m>>a>>b;
    for(int i=1;i<=n;i++)ed[i].clear();
    for(int i=1;i<=n;i++)
    {
    	visa[i]=0;
    	visb[i]=0;
	}
	//建图
    for(int i=1;i<=m;i++)
    {
    	int u,v;
    	cin>>u>>v;
    	ed[u].push_back(v);
    	ed[v].push_back(u);
	}
	na=0,nb=0;
	dfsa(a);
	dfsb(b);
	//乘法原理
	cout<<(n-na-1)*(n-nb-1)<<'\n';
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t=1;
	cin>>t;
	while(t--)solve();
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值