网络流24题-方格取数

题目

方格中取数若干,两两不相邻,求最大选数和。

样例:

3 3

1 2 3

3 2 3

2 3 1

输出:

11

ans=2+3+3+3=11

黑白染色

建成二分图:

中间这些边连成INF(即不限制流量)

其实就是求最大独立集

定理:|二分图最大独立集|=|顶点数|-|二分图最大匹配数|

这个,我不会证明。

所以:|二分图最大独立集|=|总价值|-|二分图最大匹配价值|

考虑构图:s=>黑点=>白点=>t

首先,对与第[i][j]格,有价值为val[i][j]

edge(s,黑点,val[i][j])

edge(白点,t,val[i][j])

然后,对所有黑点

edge(黑点,相邻白点,INF)

令,|总价值|=sum=∑∑val[i][j] (1<=i<=n,1<=j<=m)

|二分图最大匹配价值|<=>|最小割|<=>|最大流| 这个就不分析了。

ans=sum-MaxFlow(G)

于是,代码呼之欲出

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 #include <vector>
  7 #include <cmath>
  8 #include <queue>
  9 #include <map>
 10 #include <set>
 11 using namespace std;
 12
 13 inline void read(int &ans){
 14   ans=0;char x=getchar();int f=1;
 15   while(x<‘0‘||x>‘9‘){if(x==‘-‘)f=-1;x=getchar();}
 16   while(x>=‘0‘&&x<=‘9‘)ans=ans*10+x-‘0‘,x=getchar();
 17   ans*=f;
 18 }
 19 const int MAXN=30+10;
 20 const int MAXV=MAXN*MAXN;
 21 const int MAXE=MAXV<<4;
 22 const int INF=2e9;
 23 struct net{int v,next,c;}E[MAXE];
 24 int head[MAXV],tot,n,m;
 25 int vis[MAXN][MAXN],val[MAXN][MAXN],cnt;
 26 void edge(int u,int v,int c){
 27   E[tot]=(net){v,head[u],c},head[u]=tot++;
 28   E[tot]=(net){u,head[v],0},head[v]=tot++;
 29 }
 30 struct Net{
 31   int s,t;
 32   int dep[MAXV],cur[MAXV];
 33   void init(int a,int b){
 34     s=a,t=b,memset(head,-1,sizeof(head));
 35   }
 36   bool bfs(){
 37     memset(dep,0,sizeof(dep));
 38     queue<int>q;
 39     dep[s]=1,q.push(s);
 40     while(!q.empty()){
 41       int u=q.front();q.pop();
 42       for(int i=head[u];~i;i=E[i].next){
 43     int v=E[i].v;
 44     if(!dep[v]&&E[i].c>0){
 45       dep[v]=dep[u]+1;
 46       q.push(v);
 47     }
 48       }
 49       if(dep[t])return true;
 50     }
 51     return false;
 52   }
 53   int dfs(int u,int f){
 54     if(u==t)return f;
 55     int ans=0,cup;
 56     for(int &i=cur[u];~i;i=E[i].next){
 57       int v=E[i].v;
 58       if(E[i].c>0&&dep[v]==dep[u]+1){
 59     cup=dfs(v,min(f-ans,E[i].c));
 60     E[i].c-=cup;
 61     E[i^1].c+=cup;
 62     ans+=cup;
 63     if(ans==f)return ans;
 64       }
 65     }
 66     return ans;
 67   }
 68   int work(){
 69     int ans=0;
 70     while(bfs()){
 71       for(int i=0;i<=t;i++)cur[i]=head[i];
 72       ans+=dfs(s,INF);
 73     }
 74     return ans;
 75   }
 76 }a;
 77
 78 int Tx[4]={1,-1,0,0};
 79 int Ty[4]={0,0,-1,1};
 80 int main(){
 81   read(n),read(m);
 82   int s=n*m+1,t=s+1;
 83   a.init(s,t);
 84   for(int i=1;i<=n;i++)
 85     for(int j=1;j<=m;j++)
 86       read(val[i][j]),vis[i][j]=++cnt;
 87   int SUM=0;
 88   for(int i=1;i<=n;i++)
 89     for(int j=1;j<=m;j++){
 90       SUM+=val[i][j];
 91       if((i+j)&1)edge(s,vis[i][j],val[i][j]);
 92       else       edge(vis[i][j],t,val[i][j]);
 93       int I,J;
 94       if((i+j)&1)
 95     for(int k=0;k<4;k++){
 96       I=i+Tx[k],J=j+Ty[k];
 97       if(I<1||I>n||J<1||J>m)continue;
 98       edge(vis[i][j],vis[I][J],INF);
 99     }
100     }
101   cout<<SUM-a.work()<<endl;
102   return 0;
103 }
时间: 2024-10-13 02:00:17

网络流24题-方格取数的相关文章

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白

网络流 24题 方格取数

方格取数问题 题目描述 在一个有m*n个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第1行有2个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数.(0 <= m, n <= 30) 输出格式 取数的最大总和. 输入样例 33 1 2 3 3 2 3 2 3 1 输出样例 11 题目大意:     给出m*n的格子,相邻的格子的值不可同时取,最

[网络流24题] 方格取数问题

题面: 传送门 思路: 相邻的点不能同时取,那么在这个图中,实际上分了两种格子,每种格子相互之间随便取 那么就是二分图了 把相邻的点之间连边,得到一个二分图,我们实际上就是要求这个图的带权最大独立集 于是这道题转化为二分图问题,而二分图中最大独立集等于全集减去最小点覆盖,最小点覆盖等于这个图的最大匹配(都带权) 那么用网络流做就好了 将这个平面上的方格像国际象棋那样黑白染色 源点连黑点,容量为黑点权值 黑点连白点,容量为inf 白点连汇点,容量为白点权值 跑S-T最大流(即S-T最小割),用所有

[luogu2774] [网络流24题] 方格取数问题

传送门 某个方格如果选了,那么其周边的四个方格都不能选,有点二分图染色的味道. 考虑建立一个二分图.源点向\(x+y\)是奇数的连边,是偶数的向汇点连边. 然后根据最大和 = 全局和 - 舍弃和 = 全局和 - 最大流,求解 可以理解为在这个二分图中存在一个简单割,有一些点就被舍弃掉了,剩下的点就是我们要需选取的. #include <queue> #include <cstdio> #include <cstring> #include <algorithm&g

XTU 二分图和网络流 练习题 C. 方格取数(1)

C. 方格取数(1) Time Limit: 5000ms Memory Limit: 32768KB 64-bit integer IO format: %I64d      Java class name: Main 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output 对

网络流 [HDU 1565] 方格取数(1)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5961    Accepted Submission(s): 2268 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

网络流24题小结

网络流24题 前言 网络流的实战应用篇太难做了,因此先完善这一部分 ## 第一题:飞行员配对方案 \(BSOJ2542\)--二分图 最优匹配 题意 两国飞行员\(x\)集合\(y\)集合,\(x\)飞行员可以配对特定的\(y\)集合的飞行员(可无),求一对一配对最大数 Solution 二分图最大匹配裸题,最大流实现 建图:(设\(i\in x\)而\(i'\in y\)) \((S,i,1)~(i',T,1)\) 对\((i,j')\)可匹配\((i,j',1)\) Code 略 ## 第二

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数

「网络流24题」 9. 方格取数问题

「网络流24题」 9. 方格取数问题 <题目链接> 二分图的最大点权独立集 建立二分图,使得每个点与其相邻的点在不同的部. 源向X部引有向边,Y部向汇引有向边,边权为点权. X部每个点到其相邻的点引有向边,边权INF,这个边的两个断电不能同时被选. 那么S-X-Y-T的任意一条增广路都表示选了两个相邻的点. 于是问题转化为求网络最小割. 最终的答案为所有点的点权和(先都选上)减去网络最小割(不能选的最小点权集). #include <algorithm> #include <