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;
}
相关推荐
David猪大卫29 分钟前
【Linux修炼】环境变量、进程地址空间
linux·c语言·经验分享·笔记·学习·ubuntu·centos
xiaoye-duck3 小时前
《C++ 项目:手写大模型接入 SDK》Gemini接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型
nice_lcj5205 小时前
Java Lambda 表达式入门:怎么写、怎么用、常用方法有哪些
java·开发语言·后端·面试
码农小河665 小时前
基于SSM+JSP+MySQL的在线医疗服务系统的设计与实现
java·开发语言·mysql
Zwawa8 小时前
两根线怎么挂住一堆设备:I2C 协议原理
c语言·单片机·嵌入式
nice_lcj52010 小时前
ThreadLocal 入门:它是怎么隔离数据的、为什么会导致内存泄漏
java·开发语言·后端·面试·并发编程·内存泄漏·threadlocal
紧跟先前的步伐10 小时前
Go AI Agent 实战 28|Agent 的预算、超时与停止条件
开发语言·人工智能·后端·ai·golang
武子康10 小时前
h3.c 的两个权重槽,怎样把内存压力换成 SSD 等待
c语言·人工智能·agent
bksczm11 小时前
InnoDB 行格式详解:DYNAMIC / COMPACT / COMPRESSED / REDUNDANT
java·开发语言·数据库
春涧草茶11 小时前
慢就是快16-1协程
开发语言·前端·python