原文地址:http://www.cnblogs.com/GXZlegend


题目描述

文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过)
小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想知道,大家应该如何选择,才能使所有人的满意值之和最大。请告诉他这个最大值。

输入

第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];

输出

输出为一个整数,表示最大的满意值之和

样例输入

3 4
13 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

样例输出

152


题解

网络流最小割,和 bzoj3438 差不多。

具体做法:

1.S向每个学生连边,容量为理科收益;每个学生向T连边,容量为文科收益。

2.将每个学生组合拆成两个,S与第一个连边,容量为全理科收益,第一个向组合中学生连边,容量为inf;

组合中学生向第二个连边,容量为inf,第二个向T连边,容量为全文科收益。

3.跑最小割,答案为总收益-mincut。

#include <cstdio>
#include <cstring>
#include <queue>
#define inf 0x3fffffff
using namespace std;
queue<int> q;
int head[40000] , to[300000] , val[300000] , next[300000] , cnt = 1 , s , t , dis[40000];
void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
int x , i;
while(!q.empty()) q.pop();
memset(dis , 0 , sizeof(dis));
dis[s] = 1 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if(to[i] == t) return 1;
q.push(to[i]);
}
}
}
return 0;
}
int dinic(int x , int low)
{
if(x == t) return low;
int temp = low , i , k;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i] , min(temp , val[i]));
if(!k) dis[to[i]] = 0;
val[i] -= k , val[i ^ 1] += k;
if(!(temp -= k)) break;
}
}
return low - temp;
}
int main()
{
int n , m , i , x , ans = 0;
scanf("%d%d" , &n , &m);
s = 0 , t = 3 * n * m + 1;
for(i = 1 ; i <= n * m ; i ++ ) scanf("%d" , &x) , add(s , i , x) , ans += x;
for(i = 1 ; i <= n * m ; i ++ ) scanf("%d" , &x) , add(i , t , x) , ans += x;
for(i = 1 ; i <= n * m ; i ++ )
{
scanf("%d" , &x) , add(s , i + n * m , x) , add(i + n * m , i , inf) , ans += x;
if(i % m != 0) add(i + n * m , i + 1 , inf);
if(i % m != 1) add(i + n * m , i - 1 , inf);
if(i > m) add(i + n * m , i - m , inf);
if(i <= (n - 1) * m) add(i + n * m , i + m , inf);
}
for(i = 1 ; i <= n * m ; i ++ )
{
scanf("%d" , &x) , add(i + 2 * n * m , t , x) , add(i , i + 2 * n * m , inf) , ans += x;
if(i % m != 0) add(i + 1 , i + 2 * n * m , inf);
if(i % m != 1) add(i - 1 , i + 2 * n * m , inf);
if(i > m) add(i - m , i + 2 * n * m , inf);
if(i <= (n - 1) * m) add(i + m , i + 2 * n * m , inf);
}
while(bfs()) ans -= dinic(s , inf);
printf("%d\n" , ans);
return 0;
}

最新文章

  1. IOS Socket 02-Socket基础知识
  2. 在SQL Server 2014里可更新的列存储索引 (Updateable Column Store Indexes)
  3. Redis和Memcache的区别分析
  4. angularJS项目-ajax事件的按钮loading和页面loading状态 &amp; Controller之间通信-待续
  5. .NET设计模式(6):原型模式(Prototype Pattern)(转)
  6. (转)Asp.net的HttpCookie写入汉字读取时为乱...
  7. hibernate+spring的整合思路加实例(配图解)
  8. WinForm、wpf、silverlight三者关系
  9. SharePoint 2013 图文开发系列之列表定义高级篇
  10. 【2017-02-23】switch...case...和for循环
  11. web worker 扫盲篇
  12. sqlserver的四种分页方式
  13. 请给你的短信验证码接口加上SSL双向验证
  14. Saltstack_使用指南04_数据系统-Grains
  15. 【Diary】期中考+春游记
  16. VSCode插件开发全攻略(六)开发调试技巧
  17. 【BZOJ5323】[JXOI2018]游戏(组合计数,线性筛)
  18. meta总结
  19. input框中自动展示当前日期 yyyy/mm/dd
  20. Why is long2ip conversion important?

热门文章

  1. android design 新控件
  2. Python函数及参数
  3. html常用的实体符号
  4. 多通道CNN
  5. 01 mysql 基础一 (进阶)
  6. Pythond函数的参数使用操作注意事项
  7. 关于SSM框架项目中jsp页面EL表达式使用的一些疑问(一)
  8. Too many parameters: expected 1, was given 2 Query: SELECT count(id) FROM `user` WHERE username = ?; Parameters: [org.apache.commons.dbutils.handlers.ScalarHandler@453da22c, [李明]]
  9. TensorFlow验证码识别
  10. Android面试收集录10 LruCache原理解析