【网络流24题】No.9 方格取数问题 (二分图点权最大独立集)

【题意】

  在一个有 m*n 个方格的棋盘中, 每个方格中有一个正整数。 现要从方格中取数, 使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。

输入文件示例
input.txt
3 3
1 2 3
3 2 3
2 3 1

输出文件示例
output.txt
11

【分析】

  方格的行列之和的奇偶构成二分图,转化成二分图点权最大独立集。

  相邻的建边。

  假设所有点都能取,

  st->u 流量w[u] u的行列和为偶数

  v->ed 流量为w[v]  v的行列和为奇数

  u,v相邻 u->v 流量为INF 表示若u->v 相邻,必定要去掉一个(即割掉与源点或汇点的一条边)

  就是最小割。

  用sum-最小割即为答案。

  二分图点权最大独立集是很经典的模型。

  傻逼的我还没看出来二分图以为会算重复,真是。。。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<cmath>
  8 using namespace std;
  9 #define Maxn 1010
 10 #define INF 0xfffffff
 11
 12 struct node
 13 {
 14     int x,y,f,o,next;
 15 }t[Maxn*1010];int len;
 16 int first[Maxn];
 17
 18 int mymin(int x,int y) {return x<y?x:y;}
 19 int mymax(int x,int y) {return x>y?x:y;}
 20
 21 void ins(int x,int y,int f)
 22 {
 23     t[++len].x=x;t[len].y=y;t[len].f=f;
 24     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 25     t[++len].x=y;t[len].y=x;t[len].f=0;
 26     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 27 }
 28
 29 int st,ed;
 30 queue<int > q;
 31 int dis[Maxn];
 32 bool bfs()
 33 {
 34     while(!q.empty()) q.pop();
 35     memset(dis,-1,sizeof(dis));
 36     q.push(st);dis[st]=0;
 37     while(!q.empty())
 38     {
 39         int x=q.front();
 40         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 41         {
 42             int y=t[i].y;
 43             if(dis[y]==-1)
 44             {
 45                 dis[y]=dis[x]+1;
 46                 q.push(y);
 47             }
 48         }
 49         q.pop();
 50     }
 51     if(dis[ed]==-1) return 0;
 52     return 1;
 53 }
 54
 55 int ffind(int x,int flow)
 56 {
 57     if(x==ed) return flow;
 58     int now=0;
 59     for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 60     {
 61         int y=t[i].y;
 62         if(dis[y]==dis[x]+1)
 63         {
 64             int a=ffind(y,mymin(flow-now,t[i].f));
 65             t[i].f-=a;
 66             t[t[i].o].f+=a;
 67             now+=a;
 68         }
 69         if(now==flow) break;
 70     }
 71     if(now==0) dis[x]=-1;
 72     return now;
 73 }
 74
 75 void output()
 76 {
 77     for(int i=1;i<=len;i+=2)
 78      printf("%d->%d %d\n",t[i].x,t[i].y,t[i].f);
 79 }
 80
 81 int max_flow()
 82 {
 83     int ans=0;
 84     while(bfs())
 85     {
 86         ans+=ffind(st,INF);
 87     }
 88     return ans;
 89 }
 90
 91 int bx[6]={0,0,1,0,-1},
 92     by[6]={0,1,0,-1,0};
 93
 94 int main()
 95 {
 96     int n,m,sum=0;
 97     scanf("%d%d",&n,&m);
 98     st=n*m+1;ed=st+1;
 99     for(int i=1;i<=n;i++)
100      for(int j=1;j<=m;j++)
101      {
102          int x,now=(i-1)*m+j;
103          scanf("%d",&x);
104          sum+=x;
105          if((i+j)%2==0) ins(st,now,x);
106          else ins(now,ed,x);
107      }
108     for(int i=1;i<=n;i++)
109      for(int j=1;j<=m;j++)
110      {
111          int now=(i-1)*m+j;
112          for(int k=1;k<=4;k++) if(i+bx[k]>=1&&i+bx[k]<=n&&j+by[k]>=1&&j+by[k]<=m)
113          {
114              int nn=(i+bx[k]-1)*m+j+by[k];
115              if((i+j)%2==0) ins(now,nn,INF);
116              else ins(nn,now,INF);
117          }
118      }
119     int x=max_flow();
120     printf("%d\n",sum-x);
121     return 0;
122 }

2016-11-04 15:32:42

时间: 2024-11-05 13:45:12

【网络流24题】No.9 方格取数问题 (二分图点权最大独立集)的相关文章

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

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

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

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

【网络流24题----09】方格取数问题

«问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.«编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.«数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数.«结果输出:程序运行结束时,将取数的最大总和输出到文件grid.out中.输入文件示例 输出文件示例gr

【网络流24题9】方格取数问题

题面戳我 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. 输入格式: 第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数.接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数. 输出格式: 程序运行结束时,将取数的最大总和输出 输入输出样例 输入样例#1: 3 3 1 2 3 3 2 3 2 3

hdu1569 方格取数(2) 二分图最大点权独立集

题意:中文题.. 思路:首先根据横纵坐标之和的奇偶转化成二分图,对于( i , j )来说与它冲突的只有(i - 1 , j ) ( i , j - 1 ) ( i + 1 , j ) ( i  , j + 1 )4个方格, 奇偶性相反.如果i + j是奇数那么和周围4点连边,那么问题转化求所有点权和 - 该二分图的最小点权覆盖 .我们关注最小点权覆盖 模型,建立超级起点st,超级终点ed, 对于二分图左边的点( i+j为奇数) ,从st向点连一条边,边权为该点的权值,对于二分图右边的 点,从点

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,分别表示棋盘的行数和列数

HDU 1565:方格取数(1)(最大点权独立集)***

http://acm.hdu.edu.cn/showproblem.php?pid=1565 题意:中文. 思路:一个棋盘,要使得相邻的点不能同时选,问最大和是多少,这个问题就是最大点权独立集. 可以转化为所有的点权 - 最小点权覆盖集(最小割) = 最大点权独立集. 转载两个的定义:这里. 覆盖集(vertex covering set,VCS)是无向图的一个点集,使得该图中所有边都至少有一个端点在该集合内.形式化的定义是点覆盖集为G'VV∈(,)uvE∀∈,满足对于,都有 或成立,即,'uV

[luoguP2774] 方格取数问题(最大点权独立集)

传送门 引入两个概念: 最小点权覆盖集:满足每一条边的两个端点至少选一个的最小权点集. 最大点权独立集:满足每一条边的两个端点最多选一个的最大权点集. 现在对网格染色,使得相邻两点颜色不同,之后把两个颜色的点分成两个集合X,Y.S向X集合每个点连一条该点权值的边,Y集合每个点向T连一条该点权值的边,原来的边流量全部变为INF.这个网络的最小割为最小点权覆盖集.因为这个最小割满足了,对于中间每一条边,两端的点必定选择了一个.若一个都没有选择则S与T仍连通.且因为中间的边流量为INF所以不会是中间被

「网络流24题」 题目列表

「网络流24题」 题目列表 序号 题目标题 模型 题解 1 飞行员配对方案问题 二分图最大匹配 <1> 2 太空飞行计划问题 最大权闭合子图 <2> 3 最小路径覆盖问题 二分图最小路径覆盖 <3> 4 魔术球问题 <4> 5 圆桌问题 <5> 6 最长递增子序列问题 <6> 7 试题库问题 <7> 8 机器人路径规划问题 <8> 9 方格取数问题 二分图最大点权独立集 <9> 10 餐巾计划问题

「网络流24题」 5. 圆桌问题

「网络流24题」 5. 圆桌问题 <题目链接> 二分图多重匹配. 多对多. 匈牙利似乎真的不太好办了. 所以乖乖最大流吧. 套路建模,S->每个单位(边权=单位代表数):每个餐桌->T(边权=餐桌容量):每个单位->每个餐桌(边权=1). 跑最大流. 最大流等于总代表数则有解,否则无解. 每个单位的出边中,每条满流边的终点便是这一单位每个代表的餐桌号. #include <algorithm> #include <climits> #include &