Problem F 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?
Input
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
Output one line containing the total number of electrical devices Adam can power.
Sample Input 1 Sample Output 1
3 6 8
1 1
1 2
1 3
2 3
2 4
3 4
3 5
3 6
5
GCPC 2017 Problem F: Plug It In! 11
Sample Input 2 Sample Output 2
4 5 11
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 4
4 5
5
Sample Input 3 Sample Output 3
3 5 7
1 1
1 2
2 2
2 3
2 4
3 4
3 5

题意:

n个插头,m个插座,可以选择一个插座插3个,其他的只能插一个,最多能插多少插头

题解:

一开始先做一遍二分图,接下来我们只要对每个插座找有没有插头本来是匹配在a插座转换到b插座,a插座由另外一个插头接上,然后找出最大可以移几个
举个例子:
3 5 7
1 1
1 4
2 1
2 2
2 3
3 2
3 5
第一遍二分图之后是1-4,2-1,3-2,接下来第一遍循环找1,不说了,直接看找2,画个图就可以看出2分成3个插座是最优的
一开始2找到了1,发现1和2连着,继续。
接下来2开始找2,发现2连着3,3连着5,5未匹配,那么3连5,2连2,返回1
接下来重新找1,2发现和2连着,找到3的时候发现3未匹配,那么2就连到3,返回1
所以最大的就是5

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+5;
int line[N][N],boy[N],used[N],vis[N];
int n,m;
int Find(int x)
{
     int i,j;
     for(i=1;i<=m;i++)
     {
         if(line[x][i]==1&&used[i]==0) //如果男生x与女生i有联系并且这个女生没有被当前这一轮的男生找过,就找这个女生
         {
             used[i]=1;
             if(boy[i]==0||Find(boy[i])) //如果这个女生没有被别的男生找过或者找这个女生的男生还能找到别的女生,更新
             {
                 boy[i]=x;
                 return 1;
             }
         }
     }
     return 0;
}
int Find1(int x)
{
     int i,j;
     for(i=1;i<=m;i++)
     {
         if(line[x][i]==1&&used[i]==0)
         {
             used[i]=1;
             if(vis[i]!=x&&(vis[i]==0||Find1(vis[i])))
             {
                 vis[i]=x;
                 return 1;
             }
         }
     }
     return 0;
}
int main()
{
     int i,j,k,x,y,sum;
     scanf("%d%d%d",&n,&m,&k);
     for(i=0;i<k;i++)
     {
         scanf("%d%d",&x,&y);
         line[x][y]=1;
     }
     sum=0;
     for(i=1;i<=n;i++)
     {
         memset(used,0,sizeof(used));
         if(Find(i)) sum++;
     }
     int add=0,ans=0;
     for(int i=1;i<=n;i++)
     {
         add=0;
         for(int j=1;j<=m;j++)
            vis[j]=boy[j];
         memset(used,0,sizeof(used));
         if(Find1(i))
         {
             add++;
             memset(used,0,sizeof(used));
             if(Find1(i))
                add++;
         }
         ans=max(ans,sum+add);
     }
     printf("%d\n",ans);
     return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值