博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流
阅读量:5316 次
发布时间:2019-06-14

本文共 3838 字,大约阅读时间需要 12 分钟。

«问题描述:

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

【问题分析】

二分图点权最大独立集,转化为最小割模型,从而用最大流解决。

【建模方法】

首先把棋盘黑白染色,使相邻格子颜色不同,所有黑色格子看做二分图X集合中顶点,白色格子看做Y集合顶点,建立附加源S汇T。

1、从S向X集合中每个顶点连接一条容量为格子中数值的有向边。

2、从Y集合中每个顶点向T连接一条容量为格子中数值的有向边。
3、相邻黑白格子Xi,Yj之间从Xi向Yj连接一条容量为无穷大的有向边。

求出网络最大流,要求的结果就是所有格子中数值之和减去最大流量。

【建模分析】

这是一个二分图最大点权独立集问题,就是找出图中一些点,使得这些点之间没有边相连,这些点的权值之和最大。独立集与覆盖集是互补的,求最大点权独立集可以转化为求最小点权覆盖集(最小点权支配集)。最小点权覆盖集问题可以转化为最小割问题解决。结论:最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流。

对于一个网络,除去冗余点(不存在一条ST路径经过的点),每个顶点都在一个从S到T的路径上。割的性质就是不存在从S到T的路径,简单割可以认为割边关联的非ST节点为割点,而在二分图网络流模型中每个点必关联到一个割点(否则一定还有增广路,当前割不成立),所以一个割集对应了一个覆盖集(支配集)。最小点权覆盖集就是最小简单割,求最小简单割的建模方法就是把XY集合之间的变容量设为无穷大,此时的最小割就是最小简单割了。

/*  * Problem: 线性规划与网络流24题 #9 方格取数问题 * Author: Guo Jiabao * Time: 2009.6.27 19:06 * State: Solved * Memo: 网络最大流 二分图点权最大独立集*/#include 
#include
#include
#include
#include
using namespace std;const int MAXL=50,MAXN=50*50,MAXM=MAXN*8,INF=~0U>>1;const int dx[]={
0,0,-1,1},dy[]={-1,1,0,0};struct edge{ edge *next,*op; int t,c;}*V[MAXN],*P[MAXN],ES[MAXM],*Stae[MAXN];int N,M,S,T,C,EC,Ans,Maxflow,Total;int Lv[MAXN],Stap[MAXN],Map[MAXL][MAXL];inline void addedge(int a,int b,int c){ ES[++EC].next = V[a]; V[a]=ES+EC; V[a]->t=b; V[a]->c=c; ES[++EC].next = V[b]; V[b]=ES+EC; V[b]->t=a; V[b]->c=0; V[a]->op = V[b]; V[b]->op = V[a];}void init(){ int i,j,k,c; freopen("grid.in","r",stdin); freopen("grid.out","w",stdout); scanf("%d%d",&M,&N); S=0; T=N*M+1; for (i=1;i<=M;i++) { for (j=1;j<=N;j++) { scanf("%d",&c); Total += c; Map[i][j] = ++C; if ((i+j)%2==0) addedge(S,C,c); else addedge(C,T,c); } } for (i=1;i<=M;i++) { for (j=1;j<=N;j++) { if ((i+j)%2==0) { for (k=0;k<4;k++) { int x=i+dx[k],y=j+dy[k]; if (x>=1 && x<=M && y>=1 && y<=N) addedge(Map[i][j],Map[x][y],INF); } } } }}bool Dinic_Label(){ int head,tail,i,j; Stap[head=tail=0]=S; memset(Lv,-1,sizeof(Lv)); Lv[S]=0; while (head<=tail) { i=Stap[head++]; for (edge *e=V[i];e;e=e->next) { j=e->t; if (e->c && Lv[j]==-1) { Lv[j] = Lv[i]+1; if (j==T) return true; Stap[++tail] = j; } } } return false;}void Dinic_Augment(){ int i,j,delta,Stop; for (i=S;i<=T;i++) P[i] = V[i]; Stap[Stop=1]=S; while (Stop) { i=Stap[Stop]; if (i!=T) { for (;P[i];P[i]=P[i]->next) if (P[i]->c && Lv[i] + 1 == Lv[j=P[i]->t]) break; if (P[i]) { Stap[++Stop] = j; Stae[Stop] = P[i]; } else Stop--,Lv[i]=-1; } else { delta = INF; for (i=Stop;i>=2;i--) if (Stae[i]->c < delta) delta = Stae[i]->c; Maxflow += delta; for (i=Stop;i>=2;i--) { Stae[i]->c -= delta; Stae[i]->op->c += delta; if (Stae[i]->c==0) Stop = i-1; } } }}void Dinic(){ while (Dinic_Label()) Dinic_Augment();}int main(){ init(); Dinic(); Ans = Total - Maxflow; printf("%d\n",Ans); return 0;}

 

转载于:https://www.cnblogs.com/Aragaki/p/7554744.html

你可能感兴趣的文章
2018.11.06 bzoj1040: [ZJOI2008]骑士(树形dp)
查看>>
2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)
查看>>
redis cluster 集群资料
查看>>
微软职位内部推荐-Sr. SE - Office incubation
查看>>
微软职位内部推荐-SOFTWARE ENGINEER II
查看>>
centos系统python2.7更新到3.5
查看>>
【Quartz】常用方法的使用方式(三)
查看>>
MVVM模式下关闭窗口的实现
查看>>
C#区域截图——调用API截图
查看>>
c#与java中byte字节的区别及转换方法
查看>>
A WebBrowser Toy
查看>>
用MyXls生成Excel报表(C#)
查看>>
了解WP的传感器
查看>>
阅读笔记 火球——UML大战需求分析 2
查看>>
acedEvaluateLisp函数的反汇编
查看>>
Linux无线工具详解(Wireless tools for Linux)
查看>>
RSS阅读器
查看>>
微信电脑版不断崩溃
查看>>
js链式调用
查看>>
数字统计
查看>>