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;
}
相关推荐
人邮异步社区16 分钟前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大1 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai1 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜1 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa1 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
一次旅行1 小时前
Python+大模型端到端自动化日报系统
开发语言·python·自动化
噢,我明白了3 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
mabing9933 小时前
Qt 生成条纹图
开发语言·qt
蓝悦无人机3 小时前
C++基础 — 函数总结
开发语言·c++
糖果店的幽灵3 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph