Plug It In!(二分图匹配)

题目描述
Adam just moved into his new apartment and simply placed everything into it at random. This means in particular that he did not put any effort into placing his electronics in a way that each one can have its own electric socket.
Since the cables of his devices have limited reach, not every device can be plugged into every socket without moving it first. As he wants to use as many electronic devices as possible right away without moving stuff around, he now tries to figure out which device to plug into which socket. Luckily the previous owner left behind a plugbar which turns one electric socket into 3.
Can you help Adam figure out how many devices he can power in total?

输入
The input consists of:
• one line containing three integers m, n and k, where
– m (1 ≤ m ≤ 1 500) is the number of sockets;
– n (1 ≤ n ≤ 1 500) is the number of electronic devices;
– k (0 ≤ k ≤ 75 000) is the number of possible connections from devices to sockets.
• k lines each containing two integers xi and yi indicating that socket xi can be used to power device yi .
Sockets as well as electronic devices are numbered starting from 1.
The plugbar has no cable, i.e. if it is plugged into a socket it simply triples it.

输出
Output one line containing the total number of electrical devices Adam can power.

样例输入
3 6 8
1 1
1 2
1 3
2 3
2 4
3 4
3 5
3 6

样例输出
5

思路
先跑一遍匈牙利算法,记录原始状态下的最佳匹配,然后枚举每一个插座,对于每一次枚举,复制两个与该插座有相同电器关系的插座,以实现题目条件,对复制出的插座再进行两次匈牙利算法,最后求出的最佳结果即为答案,注意每次的初始化

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int maxn=1510;
const int maxm=1510;
typedef pair<string,string> P;
const double eps=1e-8;
const double PI=acos(-1.0);
 
int g[maxn][maxn];
int linker[maxn];
int tlinker[maxn];
bool used[maxn];
int m,n,k,len;
 
inline bool dfs(int u)
{
    for(register int v=1;v<=n;++v)
    {
        if(g[u][v] && !used[v])
        {
            used[v]=true;
            if(linker[v]==-1 || dfs(linker[v]))
            {
                linker[v]=u;
                return true;
            }
        }
    }
    return false;
}
 
inline int hungry()
{
    int res=0,ans=0;;
    memset(linker,-1,sizeof(linker));
    for(int u=1;u<=m;++u)
    {
        memset(used,false,sizeof(used));
        if(dfs(u)) res++;
    }
    for(int i=1;i<=n;++i)
    {
        tlinker[i]=linker[i];
    }
    for(int u=1;u<=m;u++)
    {
        int temp=0;
        for(int i=1;i<=n;++i)
        {
            linker[i]=tlinker[i];
        }
        for(int i=1;i<=n;i++)
        {
            g[m+1][i]=g[u][i];
            g[m+2][i]=g[u][i];
        }
        memset(used,false,sizeof(used));
        if(dfs(m+1)) temp++;
        memset(used,false,sizeof(used));
        if(dfs(m+2)) temp++;
        ans=max(ans,temp+res);
    }
    return ans;
}
 
int main()
{
    ios::sync_with_stdio(false);
    cin>>m>>n>>k;
    for(register int i=0;i<k;++i)
    {
        int u,v;
        cin>>u>>v;
        g[u][v]=1;
    }
    cout<<hungry()<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值