BZOJ3894:文理分科(最大流)(同BZoj3438)
2024-10-18 21:18:26
文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠
结过)
小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行
描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择
一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式
得到:
.如果第i行第秒J的同学选择了文科,则他将获得art[i][j]的满意值,如
果选择理科,将得到science[i][j]的满意值。
.如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且
仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开
心,所以会增加same_art[i][j]的满意值。
.如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理
科,则增加same_science[i]j[]的满意值。
小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请
告诉他这个最大值。
Input
第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];
Output
输出为一个整数,表示最大的满意值之和
Sample Input Sample Output
题意:给定一个N*M的矩阵,每个格子的人可以学文或者学理,学文和学理各有一个满意度,如果以某人为中心的十字内所有人都学文或者学理都会得到一个额外满意度,求最大满意度之和。
思路:BZOJ上面有很多此类题型,用网络里解决的方案大概有两种。
解法1:直接建图求最大流,源点S为学理,汇点T为学文。然后对于学理的“组合”,加一个点W:由源点S加边指向W,容量为组合的收益;W加边指向组合的成员,容量为inf。 同样的,对于学文的“组合”,加一个点E:由E加边指向汇点T,容量为组合的收益;组合的成员加边指向E,容量为inf。 然后求出最小割。
有:ans=sum-maxflow
解法2:先假设全部学理科,再把边权做差(学理-学文的净收益),再求最大闭合权子图:原点与代价点连接,收益点与汇点连接; 收益和-最大流=最大净收益。 那么现在的基本代价或者收益是ai-bi,。然后破坏集合的代价是c1i,得到集合的收益是c2i。 差不多就酱紫。具体的请去看popoqqq的题解。
体会:解法2更有道理一些,但是解法1更通用,无论“有格外收益的组合”长什么样子,都可以轻松加边,然后求最大流。
解法1的代码:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=;
const int inf=;
int N,M,S,T,ans,maxflow;
int Laxt[maxn],To[maxn],Next[maxn],cap[maxn],cnt=;
int vd[maxn],dis[maxn];
int xx[]={,,,,-};
int yy[]={,,-,,};
void add(int u,int v,int c)
{
Next[++cnt]=Laxt[u];
Laxt[u]=cnt;
To[cnt]=v;
cap[cnt]=c;
}
int id(int u,int v){
return (u-)*M+v;
}
int sap(int u,int flow)
{
if(flow==||u==T) return flow;
int tmp,delta=;
for(int i=Laxt[u];i;i=Next[i]){
if(dis[u]==dis[To[i]]+&&cap[i]>){
tmp=sap(To[i],min(cap[i],flow-delta));
delta+=tmp;
cap[i]-=tmp;
cap[i^]+=tmp;
if(delta==flow||dis[S]>T+) return delta;
}
}
vd[dis[u]]--;
if(vd[dis[u]]==) dis[S]=T+;
vd[++dis[u]]++;
return delta;
}
int main()
{
int i,j,k,x; scanf("%d%d",&N,&M);
S=; T=*N*M+;
for(i=;i<=N;i++)
for(j=;j<=M;j++){
scanf("%d",&x); ans+=x;
add(S,id(i,j),x); add(id(i,j),S,);
}
for(i=;i<=N;i++)
for(j=;j<=M;j++){
scanf("%d",&x); ans+=x;
add(id(i,j),T,x); add(T,id(i,j),);
}
for(i=;i<=N;i++)
for(j=;j<=M;j++){
scanf("%d",&x); ans+=x;
add(S,N*M+id(i,j),x); add(N*M+id(i,j),S,);
for(k=;k<=;k++){
int x=i+xx[k],y=j+yy[k];
if(x>=&&x<=N&&y>=&&y<=M){
add(N*M+id(i,j),id(x,y),inf); add(id(x,y),N*M+id(i,j),);
}
}
}
for(i=;i<=N;i++)
for(j=;j<=M;j++){
scanf("%d",&x); ans+=x;
add(*N*M+id(i,j),T,x); add(T,*N*M+id(i,j),);
for(k=;k<=;k++){
int x=i+xx[k],y=j+yy[k];
if(x>=&&x<=N&&y>=&&y<=M){
add(id(x,y),*N*M+id(i,j),inf); add(*N*M+id(i,j),id(x,y),);
}
}
}
while(dis[S]<=T) maxflow+=sap(S,inf);
printf("%d\n",ans-maxflow);
return ;
}
最新文章
- Libevent初探
- mysql 获取当前日期及格式化 (转)
- Java基础知识系列——Exception
- 6个值得推荐的Android开源框架简介(转)
- JsonUtil对象与json互转
- AlphaMobileControls介绍
- SpringMVC批量上传
- hdu_4824_Disk Schedule(dp)
- Spring接口编程_设值注入和构造注入
- java实现简单计算器
- 从XMLHttpRequest请求响应里getResponseHeader(header)报错:Refused to get unsafe header ";**"; 问题解决
- mac OS下在控制台中发送外部邮件
- 痞子衡嵌入式:开启NXP-MCUBootUtility工具的HAB签名功能 - CST(中英双语)
- Vector与ArrayList区别
- Python之路,第十三篇:Python入门与基础13
- MYSQL存储过程中 使用变量 做表名
- Python常见问题
- Class.isAssignableFrom(Class clz)方法 与 instanceof 关键字的区别
- PowerDesigner 同步Name到Comment 及 同步 Comment 到Name
- springboot - SqlSessionFactoryBean falls in circular dependencies by Spring Boot&#39;s DataSourceInitializer
热门文章
- 简单描述DataAdapter、DataReader、DataSet、Datatable对比
- [WCF安全3]使用wsHttpBinding构建基于SSL与UserName授权的WCF应用程序
- em和px的区别一次彻底搞清楚!
- Python 的selenium使用
- server2012/win8 卸载.net framework 4.5后 无法进入系统桌面故障解决
- C#多线程3种创建Thread、Delegate.BeginInvoke、线程池
- nyoj最少乘法次数——快速幂思想
- Loadrunner 11检查点使用方法总结
- 快速切题 poj 1003 hangover 数学观察 难度:0
- poj2400