二分图最大匹配(邻接表法)
题目链接:https://cn.vjudge.net/contest/181019#problem/F
题目大意:给你一个n*n的矩阵,问你能不能从这个矩阵的所有对角线上各取一个数,这2n-1个数各不相同,如果能,输出这些数,不能就输出NO,,,这些数的范围是1-10的9次方,,,
这题用二分图匹配做,将这些对角线当做男生,将这些对角线上的数当做女生,将这个数在这条对角线上当做关系,然后就是男生去找女生,要求的是找的最多的有多少男生,如果有2n-1个男生能匹配心仪的女生,就输出YES,否则输出NO,
这题最坑的地方就是,,这些数的范围太大,不能用二维的数组来存储他们之间的关系,所以要用到邻接表来存储,,,具体实现看代码
AC代码:
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <cctype>
#include <set>
#include <ctype.h>
#include <string.h>
#define inf 999999999
#define eps 0.000001
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long ll;
const int maxn=300*300+10;
set<int>p[maxn];
vector<int>e[maxn];
map<int,int>q;
set<int>vis;//判断某个数是否已经用过
int ans[600+10];
int s[310][310];
int dfs(int x)
{
for(int i=0;i<e[x].size();i++)
{
int t=e[x][i];
if(!vis.count(t))
{
vis.insert(t);
if(!q[t]||dfs(q[t]))
{
q[t]=x;//q[t]表示t这个数(t就相当于这个女生是否名花无主或者可以换个男生对象)是否有主了
ans[x]=t;//有主了记录t这个数的主人是哪条对角线
return 1;
}
}
}
return 0;
}
int main()
{
int n;
//cin>>n;
scanf("%d",&n);
for(int i=0;i<maxn;i++)
e[i].clear();
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
//cin>>s[i][j];
scanf("%d",&s[i][j]);
if(!p[n-j+i].count(s[i][j]))
{
p[n-j+i].insert(s[i][j]);
e[n-j+i].push_back(s[i][j]);//排除一条对角线上相同的数,留下不同的数
}
}
}
int sum=0;
q.clear();
for(int i=1;i<=2*n-1;i++)
{
vis.clear();
if(dfs(i))
sum++;
}
if(sum!=2*n-1)
{
//cout<<"NO"<<endl;
printf("NO\n");
}
else
{
printf("YES\n");
for(int i=2*n-1;i>=1;i--)
{
if(i==1)
printf("%d",ans[i]);
else
printf("%d ",ans[i]);
}
printf("\n");
}
return 0;
}