【bzoj3894】文理分科

bzoj3894文理分科

求最大满意值即求最小舍弃满意度,转化为最小割问题。

假设S集为文科,T集为理科。

从s向每个点i连一条流量为art[i]的边(割掉这条边后i点属于T集合,即选择理科,舍弃文科满意度)

从每个点i向t连一条流量为sci[i]的边(同理)

加点i+n表示对于i及与i相邻点是否都选择文科的决策,i+2*n理科

从s向每个i+n连一条流量为sameart[i]的边,从每个i+n向i和i相邻点连一条流量为inf的边

(看图中下方的图:显然如果存在任意一条sci没有割掉,sameart就要割掉,即这几个人中如果存在任意一人选择理科,就不能满足几个人同时选文科的条件,舍弃sameart)

从每个i+2*n向t连一条流量为samesci[i]的边,从每个i和i相邻点向每个i+2*n连一条流量为inf的边(同理)


#include<cstdio>
int num=1,head[40005],ans,x,t,d[40005],h[40005],n,m;
struct node{int to,next,flow;}e[400005];
void add(int u,int v,int flow)
{
	e[++num]=(node){v,head[u],flow},head[u]=num;
	e[++num]=(node){u,head[v],0},head[v]=num;
}
int min(int a,int b){return a<b?a:b;}
bool bfs()
{
	for(int i=0;i<t;i++)d[i]=0;d[t]=1;
	int l=0,r=1;h[1]=t;
	while(l!=r)
	{
		int u=h[++l];
		for(int i=head[u];i;i=e[i].next)
		 if(e[i^1].flow)
		 {
		 	int v=e[i].to;
		 	if(!d[v])d[v]=d[u]+1,h[++r]=v;
		 }
	}
	return d[0];
}
int dfs(int u,int flow)
{
	if(u==t)return flow;
	int ans=0;bool used=0;
	for(int i=head[u];i;i=e[i].next)
	 if(e[i].flow)
	 {
	 	int v=e[i].to;if(d[u]!=d[v]+1)continue;
	 	int tmp=dfs(v,min(flow,e[i].flow));
	 	if(tmp)
	 	{
	 		flow-=tmp;e[i].flow-=tmp;
	 		ans+=tmp;e[i^1].flow+=tmp;used=1;
	 		if(!flow)break;
		}
	 }
	if(!used)d[u]=-1e9;
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);t=(n*m)*3+1;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	 scanf("%d",&x),ans+=x,add(0,i*m+j-m,x);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	 scanf("%d",&x),ans+=x,add(i*m+j-m,t,x);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		scanf("%d",&x);ans+=x;int id=i*m+j-m;
		add(0,id+n*m,x),add(id+n*m,id,1e9);
		if(i>1)add(id+n*m,id-m,1e9);
		if(i<n)add(id+n*m,id+m,1e9);
		if(j>1)add(id+n*m,id-1,1e9);
		if(j<m)add(id+n*m,id+1,1e9);
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		scanf("%d",&x);ans+=x;int id=i*m+j-m;
		add(id+n*m*2,t,x),add(id,id+n*m*2,1e9);
		if(i>1)add(id-m,id+n*m*2,1e9);
		if(i<n)add(id+m,id+n*m*2,1e9);
		if(j>1)add(id-1,id+n*m*2,1e9);
		if(j<m)add(id+1,id+n*m*2,1e9);
	}
	while(bfs()){int tmp=dfs(0,1e9);if(!tmp)break;ans-=tmp;}
	printf("%d\n",ans);
}

一点感想:

一定要弄清楚现在求的到底是什么,是【最小舍弃满意值】而不是【最大满意值】,我们已经装满东西了只要负责扔而不要再去想着怎么装。

像这种同时满足条件的【与】问题,尝试转化成最小割用【或】求解,即把要同时满足的条件代表的点汇集到一个加点上,然后连出一条不满足条件要舍弃的值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值