Cheeeeen the Cute Cat 2023牛客暑期多校训练营5 C

登录—专业IT笔试面试备考平台_牛客网

题目大意:给出一个n个点,n*(n-1)/2条边的二分图,保证1~n之间没有连边,n+1~2*n之间没有连边,i和i+n之间没有连边,如果i和j+n之间有连边,那么j和i+n之间没有连边,问最大匹配

1<=n<=3000

思路:如果i到j+n有边,我们就从i向j建有向边,在有向图中如果存在环,那么这个环的最大匹配数就等于环的点数,例如下图中:

Cheeeeen the Cute Cat 2023牛客暑期多校训练营5 C_第1张图片

1-2-3-4-1构成一个4个点的环,他们的匹配分别为1-6,2-7,3-8,4-5,然后我们发现建出的有向图一定是竞赛图(即去掉方向后变成完全图的图),竞赛图一定存在一条哈密顿通路(即从一个点出发,能不重复的经过所有点),哈密顿通路的路径长度也是最大匹配,如下图中哈密顿通路为1-2-3-4,匹配为1-6,2-7,3-8,所以答案至少是n-1,

Cheeeeen the Cute Cat 2023牛客暑期多校训练营5 C_第2张图片

同时竞赛图中如果存在哈密顿回路(从1个点出发经过所有不重复的点后回到起点的路径)的话,答案就是n,即上面第一张图的情况,同时由竞赛图的性质可知:竞赛图存在哈密顿回路的充要条件为该图为一强连通分量(任意两点都能互相到达,且再加一个点就不满足该条件的分量),那么我们可以用tarjan算法找到所有强连通分量,如果有大小为1的强连通分量(也就是像上面第二幅图的点4那样),这个分量无法产生匹配,除此之外的所有强连通分量都存在哈密顿回路,最大匹配就是对应分量点数,此时答案为n-1,如果所有强连通分量大小都大于等于2,答案就是n

//#include<__msvc_all_public_headers.hpp>
#include
using namespace std;
const int N = 3e3 + 5;
vectorg[N];
int dfn[N], low[N];
bool vis[N];
int cnt = 0;
int ans = 0;
stacks;
bool flag = 1;
void tarjan(int u)
{//将图拆解成强连通分量的组合
	cnt++;//访问次序
	dfn[u] = low[u] = cnt;//每个点的访问次序,在第几个强连通分量里	
	s.push(u);//储存dfs中待处理的点
	vis[u] = 1;//在栈内待处理
	for (int i = 0; i < g[u].size(); i++)
	{
		int v = g[u][i];
		if (!dfn[v])
		{//子节点没被访问过
			tarjan(v);
 			low[u] = min(low[u], low[v]);//和子节点合并成一个强连通分量
		}
		else if (vis[v])
		{//重复访问了栈内的节点
			low[u] = min(low[u], low[v]);//这两个点一定在一个强连通分量内
		}
	}
	if (dfn[u] == low[u])
	{//当前点是这个强连通分量的第一个点,也就是这个分量都已处理完毕
		//ans++;//统计强连通分量的个数
        int temp=0;//记录强连通分量的点数
		while (!s.empty() && s.top() != u)
		{//将这个强量通分量内的点全部弹出		
			vis[s.top()] = 0;//不在栈内
            temp++;
			//belong[ans].push_back(s.top())//记录每个强连通分量内的节点编号
			s.pop();
		}
        temp++;
		vis[s.top()] = 0;//第一个点也要弹出
		s.pop();
	}
    if(temp==1)
        flag=0;//存在大小为1的强连通分量,答案就是n-1
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			int x;
			cin >> x;
			if (x)
			{
				g[i].push_back(j);
			}
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (!dfn[i])//所有没处理的点都要处理
			tarjan(i);
	}
	cout << (flag ? n : n - 1) << endl;
	return 0;
}

你可能感兴趣的:(图论,dfs,c语言,开发语言)