您的位置:首页 > 理论基础 > 计算机网络

codevs 1907 方格取数 网络流

2017-07-03 21:39 267 查看
感觉自己宛如一个傻逼。

1907 方格取数 3

时间限制: 2 s

空间限制: 256000 KB

题目等级 : 大师 Master

题解

题目描述 Description

«问题描述:

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

«编程任务:

对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

输入描述 Input Description

第1 行有2 个正整数m和n,分别表示棋盘的行数

和列数。接下来的m行,每行有n个正整数,表示棋盘方格中的数。

输出描述 Output Description

将取数的最大总和输出

样例输入 Sample Input

3 3

1 2 3

3 2 3

2 3 1

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

n,m<=30

这是一道二分图带权最大独立集的题。

二分图带权最大独立集=权值和-最小点权覆盖

关于二分图带权最大独立集:

在二分图中,每个点都有一个权值,在保证两个点不相交的前提下,使所选的点权值和最大。

方法:

建一个源点s,s向二分图的左边的点(就这么说吧23333)连一条流量为点权的有向边,二分图的左边的点再向右边连一条流量为INF的边,然后右边所有点向汇点t连一条流量为该点权值的边。

最后的结果:所有点的权值和-最小割

同时这也是一道经典建模的题。

对于一个点(i,j) i+j为奇数的点肯定不与同为奇数的点有边相交,所以可以讨论i+j的奇偶将这堆点分为两部分。

可以令源点与i+j为奇的点相连,这些点再与与它有边相交的点相连,最后连向汇点就可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 100010;
const int INF = 0x73f3f3f;
const int M = 35;

struct node{
int pre,v,f;
}edge
;

int n,m;
int head
;
int a[M][M];

int num=1;
void addedge(int from,int to,int f){
num++;
edge[num].pre=head[from];
edge[num].v=to;
edge[num].f=f;
head[from]=num;
num++;
edge[num].pre=head[to];
edge[num].v=from;
edge[num].f=0;
head[to]=num;
}

int mmax=0;
int s,t;

int state
,dis
;
bool vis
;

bool bfs(){
int h=0,tail=1;
state[1]=s,vis[s]=true,dis[s]=0;
do{
h++;
int u=state[h];
for(int i=head[u];i;i=edge[i].pre){
int v=edge[i].v;
if(!vis[v]&&edge[i].f){
vis[v]=true;
tail++;
state[tail]=v;
dis[v]=dis[u]+1;
}
}
}while(h<tail);
if(vis[t]) return true;
return false;
}

inline int Min(int a,int b){
return a<b?a:b;
}

int dfs(int u,int delta){
if(u==t||delta==0) return delta;
int ans=0;
for(int i=head[u];i&δi=edge[i].pre){
int v=edge[i].v;
if(dis[v]==dis[u]+1&&edge[i].f){
int dd=dfs(v,Min(edge[i].f,delta));
ans+=dd;
delta-=dd;
edge[i].f-=dd;
edge[i^1].f+=dd;
}
}
if(!ans) dis[u]=-1;
return ans;
}

#define ms(x,y) memset(x,y,sizeof(x))
void zero(){
ms(state,0);ms(vis,0);ms(dis,0);
}

int maxflow(){
int ans=0;
while(1){
zero();
if(!bfs()) break;
ans+=dfs(s,INF);
}
return ans;
}

int main(){
scanf("%d%d",&n,&m);
s=0,t=n*m+1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
mmax+=a[i][j];
int u=(i-1)*m+j;
if((i+j)&1){
addedge(s,u,a[i][j]);
if(j>1) addedge(u,u-1,INF);
if(i>1) addedge(u,m*(i-2)+j,INF);
if(j<m) addedge(u,u+1,INF);
if(i<n) addedge(u,m*i+j,INF);
}
else addedge(u,t,a[i][j]);
}
}
/*for(int i=head[4];i;i=edge[i].pre){
printf("%d %d\n",edge[i].v,edge[i].f);
}*/
printf("%d ",mmax-maxflow());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: