【HNOI】d 最小割
【题目大意】给定一个n*m的土地,每块可以种a或b作物,每种作物在不同的位置有不同的收成,同时,有q个子矩阵中,全部种指定的作物(a或b)会有一定的加成收成,求最大收成。
【数据范围】
50% n,m<=10 q<=500
100% n,m<=100 q<=50000
首先我们解决小范围数据,比较容易的可以看出来这是一个最小割模型,先将ans+=value。我们只需要(source,i,value[i][0]),表示不种植a的代价,(i,sink,value[i][1])表示不种植b的代价。对于额外的加成,如果全是b作物,我们可以表示为(x,cur,inf),(cur,sink,value) x为矩阵中的所有点,这个表示我们只要矩阵中的任意一个元素没有种植b(也就是某个点割得与sink相连的边),那么我们都可以找到一条新的增广路,流量为value。
那么我们可以发现,这种建模的边是n*m*q级别的,因为每次我们新的cur点都与矩阵中所有的点连接了,我们需要来增加图的点的数量来减少边的数量,那么我们可以用二维st表来表示每个矩阵中的点,num[i][j][p][q]表示矩阵中i,j点为左上角,长为2^p,宽为2^q的矩阵,我们将图拆为a,b两层,分别表示a,b作物的矩阵。
因为新加入的点是为了简化之前的图的,所以我们同层的st表之间的边应该与之前连接的边的方向相同,因为我们这样做相当与把原图拆成了两部分,原图的两部分之间是互通的,所以我们也应该将两层st表之间加上双向边,如果不加这个的话,会出现由于额外价值过大导致割了连接源和汇的边而保留两个附加收成的点,这样当然是不合法的。
反思:开始建的是正方形的st表,后来发现了这种建发的诸多不便,这样不能保证图的规模,因为条形的矩阵可以卡掉这个。然后开始的图没有两层之间双向连边,所以导致了些奇奇怪怪的问题(也不奇怪,就是上述的不合法割边)。
- //By BLADEVIL
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #define maxm 2000010
- #define maxn 110
- #define inf (1000000000)
- using namespace std;
- int n,m,query;
- int source,sink,tot,l;
- int key[maxn][maxn][],num[maxn][maxn][][][];
- int pre[maxm],other[maxm],last[maxm],len[maxm];
- int que[maxm],dis[maxm];
- void connect(int x,int y,int z) {
- pre[++l]=last[x];
- last[x]=l;
- other[l]=y;
- len[l]=z;
- //printf("|%d %d %d\n",x,y,z);
- }
- bool bfs() {
- memset(dis,,sizeof dis);
- que[]=source; dis[source]=;
- int h=,t=;
- while (h<t) {
- int cur=que[++h];
- for (int p=last[cur];p;p=pre[p]) {
- if (len[p]<=) continue;
- if (!dis[other[p]]) {
- que[++t]=other[p];
- dis[other[p]]=dis[cur]+;
- if (other[p]==sink) return true;
- }
- }
- }
- return false;
- }
- int dinic(int x,int flow) {
- //printf("%d %d\n",x,flow);
- if (x==sink) return flow;
- int rest=flow;
- for (int p=last[x];p;p=pre[p]) {
- if (len[p]<=) continue;
- if (!rest) continue;
- if (dis[other[p]]!=dis[x]+) continue;
- int tmp=dinic(other[p],min(rest,len[p]));
- len[p]-=tmp; len[p^]+=tmp; rest-=tmp;
- }
- return flow-rest;
- }
- int main() {
- freopen("d.in","r",stdin); freopen("d.out","w",stdout);
- scanf("%d%d%d",&n,&m,&query);
- for (int i=;i<=n;i++)
- for (int j=;j<=m;j++) scanf("%d",&key[i][j][]);
- for (int i=;i<=n;i++)
- for (int j=;j<=m;j++) scanf("%d",&key[i][j][]);
- l=;
- for (int p=;(<<p)<=n;p++)
- for (int q=;(<<q)<=m;q++)
- for (int i=;i+(<<p)-<=n;i++)
- for (int j=;j+(<<q)-<=m;j++) {
- num[i][j][p][q][]=++tot; num[i][j][p][q][]=++tot;
- }
- source=++tot; sink=++tot;
- int ans=;
- for (int i=;i<=n;i++)
- for (int j=;j<=m;j++) {
- connect(source,num[i][j][][][],key[i][j][]); connect(num[i][j][][][],source,);
- connect(num[i][j][][][],sink,key[i][j][]); connect(sink,num[i][j][][][],);
- ans+=key[i][j][]+key[i][j][];
- }
- for (int i=;i<=n;i++)
- for (int j=;j<=m;j++)
- connect(num[i][j][][][],num[i][j][][][],inf),connect(num[i][j][][][],num[i][j][][][],);
- for (int p=;(<<p)<=n;p++)
- for (int q=;(<<q)<=m;q++)
- for (int i=;i+(<<p)-<=n;i++)
- for (int j=;j+(<<q)-<=m;j++) {
- connect(num[i][j][p][q][],num[i][j][p][q][],inf);connect(num[i][j][p][q][],num[i][j][p][q][],);
- if (q) {
- connect(num[i][j][p][q][],num[i][j][p][q-][],inf); connect(num[i][j][p][q-][],num[i][j][p][q][],);
- connect(num[i][j][p][q][],num[i][j+(<<(q-))][p][q-][],inf); connect(num[i][j+(<<(q-))][p][q-][],num[i][j][p][q][],);
- connect(num[i][j][p][q-][],num[i][j][p][q][],inf); connect(num[i][j][p][q][],num[i][j][p][q-][],);
- connect(num[i][j+(<<(q-))][p][q-][],num[i][j][p][q][],inf); connect(num[i][j][p][q][],num[i][j+(<<(q-))][p][q-][],);
- } else
- if (p) {
- connect(num[i][j][p][q][],num[i][j][p-][q][],inf); connect(num[i][j][p-][q][],num[i][j][p][q][],);
- connect(num[i][j][p][q][],num[i+(<<(p-))][j][p-][q][],inf); connect(num[i+(<<(p-))][j][p-][q][],num[i][j][p][q][],);
- connect(num[i][j][p-][q][],num[i][j][p][q][],inf); connect(num[i][j][p][q][],num[i][j][p-][q][],);
- connect(num[i+(<<(p-))][j][p-][q][],num[i][j][p][q][],inf);
- connect(num[i][j][p][q][],num[i+(<<(p-))][j][p-][q][],);
- }
- }
- while (query--) {
- int x1,y1,x2,y2,w,z,q=,p=,cur=++tot; scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&z,&w);
- ans+=w;
- while ((<<(p+))<=x2-x1+) p++;
- while ((<<(q+))<=y2-y1+) q++;
- if (z) {
- connect(cur,sink,w); connect(sink,cur,);
- connect(num[x1][y1][p][q][],cur,inf); connect(cur,num[x1][y1][p][q][],);
- connect(num[x1][y2-(<<q)+][p][q][],cur,inf); connect(cur,num[x1][y2-(<<q)+][p][q][],);
- connect(num[x2-(<<p)+][y1][p][q][],cur,inf); connect(cur,num[x2-(<<p)+][y1][p][q][],);
- connect(num[x2-(<<p)+][y2-(<<q)+][p][q][],cur,inf); connect(cur,num[x2-(<<p)+][y2-(<<q)+][p][q][],);
- } else {
- connect(source,cur,w); connect(cur,source,);
- connect(cur,num[x1][y1][p][q][],inf); connect(num[x1][y1][p][q][],cur,);
- connect(cur,num[x1][y2-(<<q)+][p][q][],inf); connect(num[x1][y2-(<<q)+][p][q][],cur,);
- connect(cur,num[x2-(<<p)+][y1][p][q][],inf); connect(num[x2-(<<p)+][y1][p][q][],cur,);
- connect(cur,num[x2-(<<p)+][y2-(<<q)+][p][q][],inf); connect(num[x2-(<<p)+][y2-(<<q)+][p][q][],cur,);
- }
- }
- while (bfs()) ans-=dinic(source,inf);
- printf("%d\n",ans);
- fclose(stdin); fclose(stdout);
- return ;
- }
【HNOI】d 最小割的更多相关文章
- BZOJ 1391: [Ceoi2008]order [最小割]
1391: [Ceoi2008]order Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1509 Solved: 460[Submit][Statu ...
- BZOJ-2127-happiness(最小割)
2127: happiness(题解) Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 1806 Solved: 875 Description 高一 ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- BZOJ3438 小M的作物(最小割)
题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=3438 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为 ...
- 最大流-最小割 MAXFLOW-MINCUT ISAP
简单的叙述就不必了. 对于一个图,我们要找最大流,对于基于增广路径的算法,首先必须要建立反向边. 反向边的正确性: 我努力查找了许多资料,都没有找到理论上关于反向边正确性的证明. 但事实上,我们不难理 ...
- bzoj1412最小割
太羞耻了,m n写反了(主要是样例n m相等) 建图方法比较高(ji)端(chu),对于可以加栅栏的地方连上1的边,然后求最小割即可 为了让代码优(suo)美(duan),我写了一个check,避免多 ...
- 【BZOJ1497】[NOI2006]最大获利 最小割
裸的最小割,很经典的模型. 建图:要求总收益-总成本最大,那么将每条弧与源点相连,流量为成本,每个收益与汇点相连,流量为收益,然后每条弧与它所能到达的收益相连,流量为inf. 与源点相连的是未被选中的 ...
- 二分图&网络流&最小割等问题的总结
二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...
- CQOI 2016 不同的最小割
题目大意:一个无向图,求所有点对不同的最小割种类数 最小割最多有n-1个,这n-1个最小割构成一个最小割树 分治法寻找n-1个最小割.对于当前点集X,任选两点为ST做最小割,然后找出与S相连的所有点和 ...
随机推荐
- eclipse 创建并运行maven web项目
这两天想在eclipse上运行maven web项目,折腾了许久,总算success啦. 1,利用eclipse创建dynamic web project(eclipse需要安装m2eclipse). ...
- anaconda安装不存在的包
Anaconda作为一个工具包集成管理工具,下载python工具包是很方便的,直接敲: conda install package_name 1 但是有时候安装一个工具包(如skimage)的时候,在 ...
- java 堆和栈的区别
1,在栈中存放的是基本类型变量和对象的引用变量,当一段代码定义一个变量时,java 就在栈内为这个变量分配内存空间,当超过变量的作用域时,java会自动回收分配的内存. 局部变量在栈内存 2,堆内存放 ...
- JSTL标签之核心标签
JSTL(JSP Standard Tag Library ,JSP标准标签库)是一个实现 Web应用程序中常见的通用功能的定制标记库集,这些功能包括迭代和条件判断.数据管理格式化.XML 操作以及数 ...
- bpf程序
bpf都是怎么起作用的? 记得bpf之前是绑定在bpf bpf作用在哪里呀?
- 委托,事件,lambda表达式
开篇说明三个点: 委托是一种类型 事件是委托的实例 lambda表达式是一个方法(匿名方法) [未完待续]
- bzoj1069-最大土地面积
题目 给定\(n\ (n\le 2000)\)个坐标,求四个坐标使得围起来的四边形面积最大. 分析 最暴力的想法是枚举四个点,然而肯定超时.接着不知道怎么想到中途相遇,然而一点关系都没有.这里用到了一 ...
- HUAS 1483 mex(莫队算法)
考虑莫队算法,对于区间减小的情况,可以O(1)解决.对于区间增加的情况,可能需要O(n)解决.好在数据不卡莫队. 1200ms过了. 离线+线段树 760ms过了. # include <cst ...
- CentOS 输入输出重定向
标准输入重定向(STDIN,文件描述符为 0):默认从键盘输入,也可从其他文件或命令中输入.(文件描述符可以省略) 标准输出重定向(STDOUT,文件描述符为 1):默认输出到屏幕.(文件描述符可以省 ...
- [2018国家集训队][UOJ449] 喂鸽子 [dp+组合数学]
题面 传送门 思路 首先,这道题是可以暴力min-max反演+NTT做出来的......但是这个不美观,我来讲一个做起来舒服一点的做法 一个非常basic的idea:我们发现在一只鸽子吃饱以后再喂给它 ...