博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3894:文理分科——题解
阅读量:6341 次
发布时间:2019-06-22

本文共 2947 字,大约阅读时间需要 9 分钟。

文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过)

小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式得到:

1.如果第i行第J列的同学选择了文科,则他将获得art[i][j]的满意值,如果选择理科,将得到science[i][j]的满意值。

2.如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开心,所以会增加same_art[i][j]的满意值。

3.如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理科,则增加same_science[i][j]的满意值。

小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请告诉他这个最大值。

网络流,虽然我知道一个比我下面说的要简单的做法,但是我忘了(滑稽。

按照最小割的套路,与S有边表示选文,与T有边表示选理。

那么S对每个人连art边权,每个人对T连sci边权。

棘手的就是处理文科和理科之间的关系。

考虑对每个人新建同文理点,向与其相邻的人(包括他自己)连INF的边(注意方向别反了),S向同文点连sameart边,同理点向T连samesci边。

(自己画一画图大概就能感受到它的正确性了)

跑一遍最大流最小割,然后用总边权减掉最大流即可。

#include
#include
#include
#include
#include
#include
#include
using namespace std;typedef long long ll;const int N=1e5+10;const int M=N*32;const int INF=1e9;inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X;}struct node{ int nxt,to,w;}edge[M];int head[N],cnt=-1,S,T;inline void add(int u,int v,int w){ edge[++cnt].to=v;edge[cnt].w=w;edge[cnt].nxt=head[u];head[u]=cnt; edge[++cnt].to=u;edge[cnt].w=0;edge[cnt].nxt=head[v];head[v]=cnt;}int lev[N],cur[N],dui[N],a[101][101],b[101][101];int da[101][101],db[101][101];bool bfs(int m){ int r=0; for(int i=1;i<=m;i++){ lev[i]=-1; cur[i]=head[i]; } dui[0]=S,lev[S]=0; int u,v; for(int l=0;l<=r;l++){ u=dui[l]; for(int e=head[u];e!=-1;e=edge[e].nxt){ v=edge[e].to; if(edge[e].w>0&&lev[v]==-1){ lev[v]=lev[u]+1; r++; dui[r]=v; if(v==T)return 1; } } } return 0;}int dinic(int u,int flow,int m){ if(u==m)return flow; int res=0,delta; for(int &e=cur[u];e!=-1;e=edge[e].nxt){ int v=edge[e].to; if(edge[e].w>0&&lev[u]
0){ edge[e].w-=delta; edge[e^1].w+=delta; res+=delta; if(res==flow)break; } } } if(res!=flow)lev[u]=-1; return res;}int dx[5]={ 0,1,0,-1,0};int dy[5]={ 1,0,-1,0,0};int main(){ memset(head,-1,sizeof(head)); int n=read(),m=read(),ans=0; S=n*m*3+1,T=S+1; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ a[i][j]=read(); ans+=a[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ b[i][j]=read(); ans+=b[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ da[i][j]=read(); ans+=da[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ db[i][j]=read(); ans+=db[i][j]; } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int now=(i-1)*m+j; add(S,now,a[i][j]); add(now,T,b[i][j]); add(S,now+n*m,da[i][j]); add(now+2*n*m,T,db[i][j]); for(int k=0;k<5;k++){ int nx=i+dx[k],ny=j+dy[k]; if(nx<1||nx>n||ny<1||ny>m)continue; int pre=(nx-1)*m+ny; add(now+n*m,pre,INF); add(pre,now+2*n*m,INF); } } } while(bfs(T))ans-=dinic(S,INF,T); printf("%d\n",ans); return 0;}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:

+++++++++++++++++++++++++++++++++++++++++++

转载于:https://www.cnblogs.com/luyouqi233/p/8651606.html

你可能感兴趣的文章
centos6.8 安装jenkins
查看>>
vue-cli3.0+node.js+axios跨域请求session不一样的问题
查看>>
C#发送DKIM签名的邮件
查看>>
python中获取字典的key列表和value列表
查看>>
Windows8中使用IE8等低版本浏览器
查看>>
[图形图像]一次光线追踪的尝试
查看>>
C# 中out,ref,params参数的使用
查看>>
玩转VIM编辑器-vim附加特性
查看>>
Ubuntu下有关Java和数据库的一些工作记录(二)
查看>>
java 线程
查看>>
MySql 时间函数
查看>>
解决php收邮件乱码问题
查看>>
linux shell中'',""和``的区别
查看>>
OceanBase数据库实践入门——手动搭建OceanBase集群
查看>>
WPF学习:3.Border & Brush
查看>>
Docker(二):微服务教程
查看>>
关于JAVA项目报表选型过程
查看>>
javascript
查看>>
Spring_MVC
查看>>
Java统计文件夹中文件总行数
查看>>