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

题面:

传送门

思路:

相邻的点不能同时取,那么在这个图中,实际上分了两种格子,每种格子相互之间随便取

那么就是二分图了

把相邻的点之间连边,得到一个二分图,我们实际上就是要求这个图的带权最大独立集

于是这道题转化为二分图问题,而二分图中最大独立集等于全集减去最小点覆盖,最小点覆盖等于这个图的最大匹配(都带权)

那么用网络流做就好了

将这个平面上的方格像国际象棋那样黑白染色

源点连黑点,容量为黑点权值

黑点连白点,容量为inf

白点连汇点,容量为白点权值

跑S-T最大流(即S-T最小割),用所有点的权值和减去最大流值,就得到了答案

因为在这个建好的网络流图里面,最大流等于最小割等于最小点覆盖

Code:

建图比较丑,请见谅

 1     #include<iostream>
 2     #include<cstdio>
 3     #include<cstring>
 4     #include<algorithm>
 5     #define inf 0x7fffffff
 6     using namespace std;
 7     inline int read(){
 8         int re=0,flag=1;char ch=getchar();
 9         while(ch>‘9‘||ch<‘0‘){
10             if(ch==‘-‘) flag=-1;
11             ch=getchar();
12         }
13         while(ch>=‘0‘&&ch<=‘9‘) re=(re<<1)+(re<<3)+ch-‘0‘,ch=getchar();
14         return re*flag;
15     }
16     inline int _min(int l,int r){return (l>r)?r:l;}
17     const int dx[5]={0,-1,0,1,0},dy[5]={0,0,-1,0,1};
18     int n,m,cnt=-1,ans,x[50][50],first[2500],dep[2500],cur[2500];
19     struct edge{
20         int to,next,w;
21     }a[500010];
22     inline void add(int u,int v,int w){
23     //    cout<<"add "<<u<<ends<<v<<ends<<w<<endl;
24         a[++cnt].to=v;a[cnt].next=first[u];first[u]=cnt;a[cnt].w=w;
25         a[++cnt].to=u;a[cnt].next=first[v];first[v]=cnt;a[cnt].w=0;
26     }
27     inline bool bfs(int s,int t){
28         int q[2500],head=0,tail=1,i,u,v;
29         for(i=s;i<=t;i++) dep[i]=inf,cur[i]=first[i];
30         q[0]=s;dep[s]=0;
31         while(head<tail){
32             u=q[head++];
33     //        cout<<"bfs "<<u<<ends<<dep[u]<<ends<<head<<ends<<tail<<endl;
34             for(i=first[u];~i;i=a[i].next){
35                 v=a[i].to;
36                 if(!a[i].w||dep[v]!=inf) continue;
37     //            cout<<"to "<<v<<endl;
38                 dep[v]=dep[u]+1;
39                 q[tail++]=v;
40             }
41     //        system("pause");
42         }
43         return dep[t]!=inf;
44     }
45     int dfs(int u,int t,int low){
46     //    cout<<"dfs "<<u<<ends<<t<<ends<<low<<endl;
47         if(u==t||!low) return low;
48         int flow=0,f,i,v;
49         for(i=cur[u];~i;i=a[i].next){
50             cur[u]=i;v=a[i].to;
51             if(dep[v]==dep[u]+1&&(f=dfs(v,t,_min(low,a[i].w)))){
52     //            cout<<"in "<<u<<" return from "<<v<<ends<<f<<endl;
53                 flow+=f;low-=f;
54                 a[i].w-=f;a[i^1].w+=f;
55                 if(!low) break;
56             }
57         }
58     //    cout<<"return "<<u<<ends<<t<<ends<<low<<ends<<flow<<endl;
59         return flow;
60     }
61     void dinic(){
62         while(bfs(0,n*m+1)) ans+=dfs(0,n*m+1,inf);
63     }
64     int main(){
65         freopen("grid.in","r",stdin);
66         freopen("grid.out","w",stdout);
67         memset(first,-1,sizeof(first));
68         int i,j,k,ti,tj;
69         n=read();m=read();
70         for(i=1;i<=n;i++) for(j=1;j<=m;j++) x[i][j]=read(),ans-=x[i][j];
71         for(i=1;i<=n;i++){
72             for(j=1;j<=m;j++){
73                 if((i+j)&1) add((i-1)*m+j,n*m+1,x[i][j]);
74                 else add(0,(i-1)*m+j,x[i][j]);
75                 if((i+j)&1) continue;
76                 for(k=1;k<=4;k++){
77                     ti=i+dx[k];tj=j+dy[k];
78                     if(ti<1||ti>n||tj<1||tj>m) continue;
79                     add((i-1)*m+j,(ti-1)*m+tj,inf);
80                 }
81             }
82         }
83         dinic();
84         printf("%d",-ans);
85     }

原文地址:https://www.cnblogs.com/dedicatus545/p/8454337.html

时间: 2024-10-15 20:56:12

[网络流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题-方格取数

题目 方格中取数若干,两两不相邻,求最大选数和. 样例: 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,黑点,va

[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 <