Problem F Plug It In!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Let_life_stop/article/details/81983182

题目链接:https://cn.vjudge.net/contest/245468#problem/F

大意:给你插座和电器的对应关系,有多个电器对应一个插座的情况,但是一个插座只能供一个电器使用,现在有一个转换头,能够将一个插座改成三个插头,问你最多能匹配多少个电器。

思路: HK(洪凯)的思路。先按照没有转换头的思路跑一下匈牙利算法。然后,遍历有多个电器对应一个插座的这种情况,再“加”上两个插座,不过加上的这两个插座,对应关系和你当前正在遍历的这个插座与灯泡的对应关系相同,然后再看一下加入的这两个插座能不能匹配到灯泡,然后求出最大匹配量。

代码:

#include<iostream>
#include<string>
#include<cstring>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
using namespace std;
#define maxn 1500+10
int m,n,k;
int vis[maxn];
int net[maxn];
int e[maxn];
int a[maxn];
vector<int >q[maxn];
vector<int >wa[maxn];
bool Find(int t)
{
    int len=q[t].size();
    for(int i=0; i<len; i++)
    {
        int temp=q[t][i];
        if(vis[temp]==0)
        {
            vis[temp]=1;
            if(net[temp]==0||Find(net[temp]))
            {
                net[temp]=t;
                return true;
            }
        }
    }
    return false;
}
int match()
{
    int ans=0;
    for(int i=1; i<=m; i++)
    {
        memset(vis,0,sizeof(vis));
        if(Find(i))ans++;
    }
    return ans;
}
int main()
{
    memset(a,0,sizeof(a));
    memset(net,0,sizeof(net));
    cin>>m>>n>>k;
    for(int i=1; i<=k; i++)
    {
        int u,v;
        cin>>u>>v;
        q[u].push_back(v);//建立插座与灯泡的对应关系,方便后面的遍历。
        a[u]++;//记录插座对应的灯泡的个数
    }
    int t=match();
    // cout<<t<<endl;
    int maxx=0;
    for(int i=1; i<=n; i++)
    {
        e[i]=net[i];
    }
    for(int i=1; i<=m; i++)
    {
        if(a[i]>1)
        {
            int s=0;
            int len=q[i].size();
            for(int k=1; k<=2; k++)
            {
                for(int j=0; j<len; j++)
                {
                    int  temp=q[i][j];
                    q[m+k].push_back(temp);
                }
            }//加上两个插座
            memset(vis,0,sizeof(vis));
            if(Find(m+1))s++;
            memset(vis,0,sizeof(vis));//注意每次对vis数组进行清空。
            if(Find(m+2))s++;
            maxx=max(s,maxx);
            q[m+1].clear();
            q[m+2].clear();//清除新加入的两个的插座的对应关系
            for(int l=1; l<=n; l++)
            {
                net[l]=e[l];
            }//在匹配新加的两个插座的时候,原来的灯泡与插座的对应关系有可能会改变,所以需要恢复到原来的对应关系
            if(t==n)break;
        }
    }
    cout<<t+maxx<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Let_life_stop/article/details/81983182