2018 BJTU Summer Training 【二分图匹配 & 网络流 & 费用流】

前言(瞎BB)

网络流是我在OI生涯学的最后一个算法,它很适合算法竞赛,因为它需要建立模型(图)来反映题目中的限制条件,而且可以得出一些最优的东西(最大流),或者是搞出方案(搜索残量网络),这些都是算法竞赛最喜欢的。

高中就听说过一位神犇,凭借一手网络流解决了许多标解不是网络流的题目,当时相信,但也就是听个说法。这个暑假做了题单上的几道题后才深刻感受到网络流的强大。

 

//感觉目前自己的网络流板子还不够完善,日后再补充,所有题目的代码直接上Vjudge搜,放在文章里太臃肿,也懒得贴了= =

190423 下面贴我用得板子,BFS改用queue,采用当前弧优化,需配合使用说明食用

//cur[]的初始化默认从S到T,如果源汇点不是最小最大点,则需要重写
//MAXN是点个数,MAXM是边个数,要考虑反边
int S,T;
int dis[MAXN];//,dl[MAXN];
int Head[MAXN],Next[MAXM],To[MAXM],FB[MAXM],Flow[MAXM],Cnt=0;//MAXM要考虑反边 
int cur[MAXN];//当前弧优化

void ADD(int x,int y,int z)
{
	Cnt++;Next[Cnt]=Head[x];Head[x]=Cnt;To[Cnt]=y;FB[Cnt]=Cnt+1,Flow[Cnt]=z;
	Cnt++;Next[Cnt]=Head[y];Head[y]=Cnt;To[Cnt]=x;FB[Cnt]=Cnt-1,Flow[Cnt]=0;
}
bool BFS(int Begin,int End)
{
	int x,X;
	memset(dis,0xff,sizeof(dis));
	dis[Begin]=0;
	queue <int> q;
	q.push(Begin);
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(int i=Head[x];i;i=Next[i])
		{
			X=To[i];
			if(Flow[i]<=0||dis[X]>=0) continue;
			dis[X]=dis[x]+1;
			q.push(X);
		}
	}
	if(dis[End]>0) return true;
	else return false;
}
int Find(int x,int MFLOW,int y)
{
	if(x==y) return MFLOW;
	int X,h; 
	for(int i=cur[x];i;i=Next[i])
	{
		cur[x]=i;
		X=To[i];
		if(Flow[i]>0&&dis[x]+1==dis[X]&&(h=Find(X,min(MFLOW,Flow[i]),y)))
		{
			Flow[i]-=h;
			Flow[FB[i]]+=h;
			return h;
		}
	}
	return 0;
}
int Solve(int x,int y)
{
	int X,Ans=0;
	while(1)
	{
		if(!BFS(x,y)) break;
		for(int i=S;i<=T;i++)//初始化全体cur 
			cur[i]=Head[i];
		while((X=Find(x,0x7fffffff,y)))
			Ans+=X;
	}
	return Ans;
}

POJ 3041 Asteroids

题意:一个n*m(n,m<=500)的矩阵中存在一些点,一次操作可以去除同一列或者同一行上所有的点,求最小的操作次数

题解:一个二分图匹配的入门题。使用到了一个二分图匹配的性质:二分图的最小顶点覆盖数 = 最大匹配数。一个二分图的最大匹配的总能使得每一条边的某一个点被覆盖,且被覆盖边的总数最小。

回到这道题目,如果(x,y)处存在一个点,那么将二分图左边x点和右边y点之间连一条边,最后跑二分图匹配即可。这样可以保证每条边都匹配上一个点,对应原题目中每个点被一种方案消除。

POJ 3281 Dining

题意:有n头奶牛,每个奶牛都有自己喜欢的一些饲料和饮料,如果一头奶牛能同时拥有自己喜欢的饲料和饮料,那么它将得到满足。每种饲料和饮料仅能供给一头奶牛,问最多能满足多少奶牛。

题解:友好的入门网络流题目,设超级源点向每个饲料连边,每种饮料向超级汇点连边,奶牛喜欢什么就给奶牛连上边,跑最大流即可。

POJ 3057 Evacuation

题意:给出一个X*Y(3 <= Y, X <= 12)的字符矩阵来表示一个房间,'X'为障碍物,'.'表示一个空地且该空地上站有一个人,'D'表示一扇门。每个人一个时间单位移动一格,每扇门一个时间单位内仅能通过一个人,每个空位上的人数不作限制。保证最外围只有障碍物或门,保证门只存在最外围。求所有人离开的最小时间。

题解:说实话,这题如果不挂在题单上,我很难想到用网络流或者说是二分图来解。每扇门的每个时间点都建一个点,然后对每个人连边。如果一个人到一扇门的距离为x,则把这个人往这扇门x时间点以后的每个点都连上一条边。

正解是二分答案,对应建图,看最大匹配是否是总人数。我采用了从小到大枚举的方法,结果超时,加了Dinic算法中的当前弧优化才勉强通过。

POJ 3469 Dual Core CPU

题意:一个CPU有A,B两个核,现在有n个任务要处理。第i个任务在A核上解决花费为ai,在B核上解决花费为Bi。还有m个约束条件,在第i个约束中,若任务li和任务ri在不同的核上解决,则产生额外花费wi。求解决所有任务的最小花费。

题解:这种带约束的任务分配问题很符合网络流的模型,但是这个数据范围着实有问题,1e5很难让我想到用网络流解决。

再说下解法。每个任务拆点为xi和yi两点,xi连yi无限流量,超级源点连一条流量为ai的边到xi,yi连一条流量为bi的边到超级汇点。这样跑最大流就是一个最小割,即最小花费。对于每个约束条件,则从li连一条流量为wi的边到ri。类似上述用最小割的性质来求最小花费的方法在网络流24题中常有,要灵活应用。

POJ 2135 Farm Tour

题意:给出一张无向图,要求从1走到n再走回1,每条路只能走一次,求最短路。

题解:用费用流来做,每条边流量为1,费用为边的长度,最后跑出最大流为2的最小费用即可。设置一个超级源点可以控制流量。

P2770 航空路线问题,这题是跑最长路,而且要输出方案,稍微难一点。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值