Plug It In! 二分图匹配,匈牙利算法扩展(图论模板题)。

没学过匈牙利算法的可以看这个:https://blog.csdn.net/ivy_uu/article/details/52091873

链式存图可以看这个:https://blog.csdn.net/weixin_43916298/article/details/86483605

转自 :https://blog.csdn.net/yz467796454/article/details/82953083

问题 E: Plug It In!

时间限制: 12 Sec  内存限制: 128 MB
提交: 86  解决: 19
[提交] [状态] [命题人:admin]

题目描述

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

题意:有m种插座编号从1到m,n种电器编号1到m,k个匹配(u,v)代表u能给v充电,但是你有一个东西能让一个u变成三个。问最多能够使得几个电器工作。

思路:典型的二分图匹配,不过不能把每一个u*3都跑一遍,会T;所以先保留不用那个东西的结果。然后对于每一个u多给他跑两次匈牙利匹配保留最大结果就可以了。

#include<bits/stdc++.h>
const int maxx=1e5+15;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const ll mod=1e9+7;
using namespace std;
ll m,n,k;	
ll cnt=0;
int head[maxx];
int vis[maxx];
int match[maxx];
int biaoji[maxx];
int mat[maxx];
struct node{
	int to,next;	
}edge[maxx];
void add(int u, int v)
{
	edge[cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt++;	
}  
int find(int x)
{
	for(int i=head[x];~i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(!vis[v])  // 还没匹配到呢。 
		{
			vis[v]=1; // 迁一条线。  
			if(match[v]==0||find(match[v])) 
			{
				match[v]=x;
				return 1;
			}
		}
	}
	return 0;
}
int insert() 
{
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		mem(vis,0);
		ans+=find(i);
	}
	return ans;	
}

int Initialization()// 初始化。 
{
	cnt=0;
	mem(head,-1);
	mem(match,0);
	mem(biaoji,0);
	scanf("%lld%lld%lld",&n,&m,&k);
	int u,v;
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);
		biaoji[u]++;
	}
}
int main()
{
	int i,j;
	Initialization();
	ll ans=insert();
	for(i=1;i<=m;i++) mat[i]=match[i];// 不用插板;
	int maxl=0;	
	int x=0;
	for(i=1;i<=n;i++)// 每一个跑两次。 
	{
		for(j=1;j<=m;j++)
		{
			match[j]=mat[j]; // 每次再赋值回去 
		} 
		x=0;
		for(j=1;j<=2;j++) // 多匹配两次
		{
			mem(vis,0);
			if(find(i)) x++;
			else break;
		}
		maxl=max(maxl,x);
	}
	ans+=maxl;
	printf("%lld\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值