BZOJ 3894: 文理分科 最小割
2016-07-08 15:22
288 查看
3894: 文理分科
题目连接:
http://www.lydsy.com/JudgeOnline/problem.php?id=3894Description
文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过)
小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想知道,大家应该如何选择,才能使所有人的满意值之和最大。请
告诉他这个最大值。
Input
第一行为两个正整数:n,m接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];
Output
输出为一个整数,表示最大的满意值之和Sample Input
3 413 2 4 13
7 13 8 12
18 17 0 5
8 13 15 4
11 3 8 11
11 18 6 5
1 2 3 4
4 2 3 2
3 1 0 4
3 2 3 2
0 2 2 1
0 2 4 4
Sample Output
152Hint
题意
题解
最小割连接S的表示选择文科,连接T的表示选择理科
对于周围的十字,那么就是表示这五个人都选的文科或者理科。
那我们连一个特殊的点就好了呀,然后文科的十字连接这个点以及这个点周围的点就好了。
理科同理。
具体建图看代码,用最小割的思想去理解,就比较简单了。
代码
#include<bits/stdc++.h> using namespace std; const int MAXN=500000,MAXM=500000,inf=1e9; struct Edge { int v,c,f,nx; Edge() {} Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {} } E[MAXM]; int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz; void init(int _n) { N=_n,sz=0; memset(G,-1,sizeof(G[0])*N); } void link(int u,int v,int c) { E[sz]=Edge(v,c,0,G[u]); G[u]=sz++; E[sz]=Edge(u,0,0,G[v]); G[v]=sz++; } bool bfs(int S,int T) { static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N); dis[S]=0; Q[0]=S; for (int h=0,t=1,u,v,it;h<t;++h) { for (u=Q[h],it=G[u];~it;it=E[it].nx) { if (dis[v=E[it].v]==-1&&E[it].c>E[it].f) { dis[v]=dis[u]+1; Q[t++]=v; } } } return dis[T]!=-1; } int dfs(int u,int T,int low) { if (u==T) return low; int ret=0,tmp,v; for (int &it=cur[u];~it&&ret<low;it=E[it].nx) { if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f) { if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f))) { ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp; } } } if (!ret) dis[u]=-1; return ret; } int dinic(int S,int T) { int maxflow=0,tmp; while (bfs(S,T)) { memcpy(cur,G,sizeof(G[0])*N); while (tmp=dfs(S,T,inf)) maxflow+=tmp; } return maxflow; } int n,m; int dx[5]={1,-1,0,0,0}; int dy[5]={0,0,1,-1,0}; int id(int x,int y){ return (x-1)*m+y; } int main(){ scanf("%d%d",&n,&m); int S=0,T=n*m*3+1; init(n*m*3+5); int ans = 0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int a;scanf("%d",&a); ans+=a; link(S,id(i,j),a); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int a;scanf("%d",&a); ans+=a; link(id(i,j),T,a); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int a;scanf("%d",&a); ans+=a; link(S,id(i,j)+m*n,a); for(int k=0;k<5;k++){ int x=dx[k]+i; int y=dy[k]+j; if(x<1||x>n||y<1||y>m)continue; link(id(i,j)+m*n,id(x,y),inf); } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int a;scanf("%d",&a); ans+=a; link(id(i,j)+2*m*n,T,a); for(int k=0;k<5;k++){ int x=dx[k]+i; int y=dy[k]+j; if(x<1||x>n||y<1||y>m)continue; link(id(x,y),id(i,j)+m*n*2,inf); } } } printf("%d\n",ans-dinic(S,T)); }
相关文章推荐
- VS CODE 下的 ESLint 安装以及使用
- C#调用Java方法(详细实例)
- javascript 引用类型 - Object类型
- Android RoundedBitmapDrawable:Android官方的圆角图形图象实现方案
- 我
- 反爬虫
- 同步和异步的概念
- CodeForces 339D Xenia and Bit Operations (线段树)
- MATLAB数学建模练习(1)-线性规划
- hibernate缓存机制详细分析
- 布局延伸到状态栏
- Linux 后台启动
- Android TextView通过Spannable识别超链接、邮箱、电话
- c 空指针
- 创建GitHub技术博客全攻略
- Java ScheduledThreadPoolExecutor延迟或周期性执行任务
- leetcode 42. Trapping Rain Water
- 在linux下使用curl访问 多参数url GET参数问题
- 百宝云注册码系统
- ButterKnife替代findViewById