网络流经典模型之一:最大权闭合子图(寿司餐厅)

前言

为毛我之前做网络流24题一篇题解都没有写

正片

例题

[六省联考2017]寿司餐厅

链接

当时就想着用DP搞,结果死活搞不出那个m=1的做法

最大权闭合子图介绍

给你新的一道题目,有 n n n个点,每个点有个 a a a值,选了就会加上其 a a a值,那么很明显加上全部正的 a a a即可。

但是现在要求给你一些关系:选了 x x x必须选 y y y

我们现在的 a n s ans ans先加上所有的正数。

那么,考虑最小割,如果在最小割中割了 x x x S S S的边,表示不选 x x x,而割了 x x x T T T的边,然后需要注意的是,边权不是价值,而是代价,也就是需要从 a n s ans ans中减去的东西。(当然,倒过来应该也没有问题。)

对于一个点 i i i,如果 a i > 0 a_i>0 ai>0,则向 S S S连边权为 a i a_i ai的边,向 T T T连边权为 0 0 0的边,如果 a i ≤ 0 a_i≤0 ai0,则向 S S S连边权为 0 0 0的边,向 T T T连边权为 − a i -a_i ai的边。

好,那么如果选了 x x x必须选 y y y,就把 x x x y y y连一条边,边权为 ∞ ∞ ,为什么?

因为如果 x x x选了,割了与 T T T的边, y y y不选,割了与 S S S的边,那么就一定存在一条路径: S − > x − > y − > T S->x->y->T S>x>y>T

所以 x x x选了, y y y必须被选。

这就是最大权闭合子图。

做法

仔细一看,对于 d i , j d_{i,j} di,j而言,选了其必须选择 d i + 1 , j , d i , j − 1 d_{i+1,j},d_{i,j-1} di+1,j,di,j1,而对于 d i , i d_{i,i} di,i而言,选了其必须删去 i i i的代号,而对于 i i i,如果其被选择,那么也要删去其代号的平方乘 m m m

然后跑Dinic即可。

代码

#include<cstdio>
#include<cstring>
#define  N  110
#define  NN  12000
#define  M  110000
using  namespace  std;
inline  int  mymin(int  x,int  y){return  x<y?x:y;}
struct  node
{
	int  y,next,c;
}a[M];int  len=1,last[NN];
inline  void  ins_node(int  x,int  y,int  c){len++;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
inline  void  ins(int  x,int  y,int  c){ins_node(x,y,c);ins_node(y,x,0);}
int  list[NN],head,tail,h[NN],st,ed;
bool  bfs()
{
	memset(h,0,sizeof(h));h[ed]=1;
	head=1;tail=1;list[1]=ed;
	while(head<=tail)
	{
		int  x=list[head++];
		for(int  k=last[x];k;k=a[k].next)
		{
			int  y=a[k].y;
			if(a[k^1].c  &&  !h[y])
			{
				h[y]=h[x]+1;
				list[++tail]=y;
			}
		}
	}
	return  h[st];
}
int  dinic(int  x,int  f)
{
	if(x==ed)return  f;
	int  s=0,t;
	for(int  k=last[x];k;k=a[k].next)
	{
		int  y=a[k].y;
		if(a[k].c  &&  h[x]==h[y]+1)
		{
			s+=t=dinic(y,mymin(f-s,a[k].c));
			a[k].c-=t;a[k^1].c+=t;
			if(s==f)return  s;
		}
	}
	h[x]=0;
	return  s;
}
bool  v[1100];
int  ans=0;
inline  void  jian(int  x,int  v)
{
	if(v>0)
	{
		ans+=v;
		ins(st,x,v);
	}
	else  if(v<0)ins(x,ed,-v);
}
int  n,m,d[N][N];
int  main()
{
	scanf("%d%d",&n,&m);
	st=n*n+n+1000+1;ed=st+1;
	for(int  i=1;i<=n;i++)
	{
		int  x;scanf("%d",&x);
		if(!v[x]  &&  m)jian(n*n+x,-m*x*x),v[x]=1;
		jian(n*n+1000+i,-x);
		ins(n*n+1000+i,n*n+x,999999999);
	}
	for(int  i=1;i<=n;i++)
	{
		for(int  j=i;j<=n;j++)
		{
			scanf("%d",&d[i][j]);
			jian((i-1)*n+j,d[i][j]);
		}
	}
	for(int  i=1;i<=n;i++)
	{
		for(int  j=i;j<=n;j++)
		{
			if(i==j)ins((i-1)*n+j,n*n+1000+i,999999999);
			else  ins((i-1)*n+j,i*n+j,999999999),ins((i-1)*n+j,(i-1)*n+j-1,999999999);
		}
	}
	while(bfs())
	{
		ans-=dinic(st,999999999);
	}
	printf("%d\n",ans);
	return  0;
}
/*
1-n^2表示d(i,j)
n^2+1-n^2+1000表示第i个代号。
n^2+1001-n^2+1000+n表示第i个数字,减去其代号 
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题编号 问题名称 问题模型 转化模型 1 飞行员配对方案问题 二分图最大匹配 网络最大 2 太空飞行计划问题 最大权闭合网络最小割 3 最小路径覆盖问题 有向无环图最小路径覆盖 网络最大 4 魔术球问题 有向无环图最小路径覆盖 网络最大 5 圆桌问题 二分图多重匹配 网络最大 6 最长递增子序列问题 最多不相交路径 网络最大 7 试题库问题 二分图多重匹配 网络最大 8 机器人路径规划问题 (未解决) 最小费用最大 9 方格取数问题 二分图点权最大独立集 网络最小割 10 餐巾计划问题 线性规划网络优化 最小费用最大 11 航空路线问题 最长不相交路径 最小费用最大 12 软件补丁问题 最小转移代价 最短路径 13 星际转移问题 网络判定 网络最大 14 孤岛营救问题 分层图最短路径 最短路径 15 汽车加油行驶问题 分层图最短路径 最短路径 16 数字梯形问题 最大权不相交路径 最小费用最大 17 运输问题 网络费用量 最小费用最大 18 分配问题 二分图最佳匹配 最小费用最大 19 负载平衡问题 最小代价供求 最小费用最大 20 深海机器人问题 线性规划网络优化 最小费用最大 21 最长k可重区间集问题 最大权不相交路径 最小费用最大 22 最长k可重线段集问题 最大权不相交路径 最小费用最大 23 火星探险问题 线性规划网络优化 最小费用最大 24 骑士共存问题 二分图最大独立集 网络最小割

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值