网络流 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的格子,相邻的格子的值不可同时取,最后求出最大值。

我还误以为只有两种情况,用暴力不就好了吗,不过wyy给我举出其他情况,事实证明我想少了。

构图:


如图,我们会发现,黑色格子都是可以同时选的,白色格子也是同时可以走的。会发现同是黑色格子(白色格子),它们的行列坐标加起来mod 2,都是一样的。

所以,我们可以用二分图来给它们归类。首先,行列之和,为偶数的放在左边,行列之和为奇数的放在右边。于是,便得出,黑色格子的放在右边,白色格子放在左边。

因为黑白之间是互不可取的,以中间的黑色格子为例,它不可达的格子有它上下左右的白色格子,于是把它们相连。同理,所有黑色格子都这么连。

并把黑色格子(行列和为偶数)与s节点相连,白色格子与t相连。

解题思想:

    求出来的为最小割,也就是说,如果经过这个点,那就是把这个点割去了,不能选。而得出最小割,也就是得出了不选哪些格子,所以,用总和减去最小割就是最后的答案。

细节:

    我们一开始一直wrong,是因为数组开小了,maxn直接开为35,可是在这一个棋盘里面,格子数是远远不止这么多的,要开到n^2。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1000,oo=10000000;//注意数组大小,格子数为n^2。
int ans;
int cur=-1,s,t,m,n;
int head[maxn],c[maxn][maxn],v[maxn],id[maxn][maxn],a[maxn][maxn];
int xx[5]={0,0,1,-1},yy[5]={1,-1,0,0};

struct space
{
	int to,next,va,type;
}edge[maxn*maxn];

void add(int from,int to,int va,int type)
{
	cur++;
	edge[cur].to=to;
	edge[cur].va=va;
	edge[cur].type=type;
	edge[cur].next=head[from];
	head[from]=cur;
}

void build(int x,int y)
{
	for(int i=0;i<4;i++)
	{
		int nowx=x+xx[i],nowy=y+yy[i];//上下左右点的坐标 

		if(nowx<1||nowx>m||nowy<1||nowy>n) continue;//判断是否有出现越界的情况 

		add(id[x][y],id[nowx][nowy],oo,0);//相连
		add(id[nowx][nowy],id[x][y],0,1);

	}
}

void init()
{
	memset(head,-1,sizeof(head));
	int k=0;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
			ans+=a[i][j];
			k++;
			id[i][j]=k;
			c[i][j]=(i%2==j%2);//记下这个格子行列之和为偶数或是奇数
		}
	}
	s=0,t=n*m+1;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(c[i][j])//如果为偶数,即图中的黑色格子
				build(i,j);
		}
	}
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(c[i][j])
			{
				add(s,id[i][j],a[i][j],0);//黑色格子与s相连,边权为a[i][j]
				add(id[i][j],s,0,1);
			}
			else
			{
				add(id[i][j],t,a[i][j],0);
				add(t,id[i][j],0,1);
			}
		}
	}
}

int dfs(int now,int mi)
{
	if(now==t) return mi;
	if(v[now]==1)	return 0;
	v[now]=1;
	int h=head[now];
	while(h!=-1)
	{
		int to=edge[h].to,va=edge[h].va;
		if(va!=0)
		{
			int k;
			k=dfs(to,min(va,mi));
			if(k!=0)
			{
				edge[h].va-=k;
				edge[h^1].va+=k;
				return k;
			}
		}
		h=edge[h].next;
	}
	return 0;
}//最小割(与最大流的代码完全是一样的) 

int main()
{
	freopen("2207.in","r",stdin);
	freopen("2207.out","w",stdout);
	cin>>m>>n;
	init();

	while(1)
	{
		memset(v,0,sizeof(v));
		int res;
		res=dfs(0,oo);
		if(res==0) break;
		ans-=res;
	}
	cout<<ans<<endl;
	return 0;
}

  

http://blog.csdn.net/u013686535/article/details/77152103

这篇博客写得比较清楚。

时间: 2024-10-25 16:30:59

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

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

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的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

[网络流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 <