题目大意:给出一个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;
}