Problem F ——Plug It In!(二分图,某个x连3个y)

原题: https://cn.vjudge.net/contest/259384#problem/F

题意:

n个插座,m个玩具,下面k行匹配关系,一个一般的插座只能插一个玩具,你可以使一个插座插三个玩具,求最大匹配数

解析:

首先对插座做一遍匈牙利,匹配完之后,再枚举每个插座,看看是不是可能再插两个玩具(也是匈牙利,因为我的匈牙利考虑的是玩具的匹配,所以可以直接对插座做匈牙利,相当于这个插座可以再多匹配一个玩具)

当然,枚举一个插座的时候,不能改变原来的玩具的匹配数组,所以要新开一个tmp数组

按照这种思路,如果遇到某些插座可以匹配k个玩具的题目,就直接对这些插座做k次匈牙利即可
当然,这时的匈牙利要进行修改来避免死循环

#include<bits/stdc++.h>
using namespace std;
const int N=1600;

int match[N];
bool vis[N];
bool link[N][N];

int f[N];
bool v[N];

int n,m;

int fin(int h){
    for(int i=1;i<=m;i++){
        if(vis[i]||!link[h][i])continue;
        vis[i]=1;
        if(match[i]==0||fin(match[i])){
            match[i]=h;return 1;
        }
    }
    return 0;
}

int tmp[N];
int fin2(int h){
    for(int i=1;i<=m;i++){
        if(vis[i]||!link[h][i])continue;
        vis[i]=1;
        if(tmp[i]!=h&&(tmp[i]==0||fin2(tmp[i]))){//避免死循环
            tmp[i]=h;return 1;
        }
    }
    return 0;
}

int main(){
	memset(match,0,sizeof(match));
	int t;
	scanf("%d%d%d",&n,&m,&t);

	for(int i=1,a,b;i<=t;i++)scanf("%d%d",&a,&b),link[a][b]=1;

    int ans=0;
    for(int i=1;i<=n;i++){//插座
        memset(vis,0,sizeof(vis));
        if(fin(i))ans++;//最大匹配数
    }
    int ma=0;
    for(int i=1;i<=n;i++){
        int add=0;
        for(int j=1;j<=m;j++)tmp[j]=match[j];
        memset(vis,0,sizeof(vis));
        if(fin2(i)){
            add++;
            memset(vis,0,sizeof(vis));
            if(fin2(i)){
                    add++;
            }
        }
        ma=max(ma,add);
    }
    printf("%d\n",ma+ans);
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/82946800
今日推荐