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建有向边,在有向图中如果存在环,那么这个环的最大匹配数就等于环的点数,例如下图中:

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,

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

cpp 复制代码
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 3e3 + 5;
vector<int>g[N];
int dfn[N], low[N];
bool vis[N];
int cnt = 0;
int ans = 0;
stack<int>s;
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;
}
相关推荐
青春逝如流水28 分钟前
Java 线程与操作系统、硬件的关系:状态、映射与差异
java·开发语言·多线程·ai文章
谢亮_vipxieliang31 分钟前
Go gRPC基础与实战
开发语言·后端·golang
Aurorar0rua1 小时前
CS50 x 2024 Notes Data structures - 08
c语言·开发语言·学习方法
企业数字化笔记1 小时前
新租户注册成功却不能用?开通状态、初始化恢复与可用性验收
开发语言·python
瑶山1 小时前
Windows + WSL2 Ubuntu + VS Code配置C++开发环境
开发语言·c++·windows·vscode·wsl
Vertira1 小时前
C# 函数封装成 DLL,
开发语言·c#
开开心心就好1 小时前
一元二次方程求解工具,答案带详细步骤
java·服务器·开发语言·算法·pdf·ocr·perl
cc5725026531 小时前
2027校招:大数据管理与应用专业做数据治理,技术之外还要准备什么?
java·开发语言
小米里的大麦1 小时前
19 C、C++ 操作 MySQL
c语言·c++·mysql
青春逝如流水1 小时前
Java 线程池的创建方式、注意要点与任务类型判断
java·开发语言·线程池·多线程·ai文章