二分图最大匹配(邻接表法)

二分图最大匹配(邻接表法)

题目链接: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值