【網絡流24題-洛谷-P2774】方格取數問題(二分圖點權最大獨立集、網絡最小割)

題目背景

none!

題目描述

在一個有 m*n 個方格的棋盤中,每個方格中有一個正整數。現要從方格中取數,使任意 2 個數所在方格沒有公共邊,且取出的數的總和最大。試設計一個滿足要求的取數算法。對於給定的方格棋盤,按照取數要求編程找出總和最大的數。

輸入格式

第 1 行有 2 個正整數 m 和 n,分別表示棋盤的行數和列數。接下來的 m 行,每行有 n 個正整數,表示棋盤方格中的數。

輸出格式

程序運行結束時,將取數的最大總和輸出

輸入輸出樣例

輸入 #1複製

3 3
1 2 3
3 2 3
2 3 1 

輸出 #1複製

11

說明/提示

m,n<=100

思路:

方格分爲兩部分,可以看成一個二分圖,假設所有點都選,那麼只要找出一部分不選的,使得這部分的值最小就可以。然後轉換到了二分圖的最小割上。起點和終點與點之間的連邊的流量爲點權,不選這個點,只要將這條邊割掉就好。這個二分圖的點的連邊,表示兩個點不能共存,所以目標是讓加入起點和終點的圖沒有從起點到終點的路徑,因此轉換到了最小割。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<bitset>
#include<time.h> 
using namespace std;
typedef long long ll;
const int inf=1e9+7;
struct node{
	int v,nxt,w;	
}e[1000005<<1];
int tot,head[10050];
int st,ed;
int dis[10050],q[10050];
void add(int u,int v,int w){
	e[tot].v=v;	e[tot].w=w;	e[tot].nxt=head[u];	head[u]=tot++;
	e[tot].v=u;	e[tot].w=0;	e[tot].nxt=head[v];	head[v]=tot++;
}
int bfs(int st,int ed){
	for(int i=st;i<=ed;i++) dis[i]=-1;
	int front=0,tail=0;
	q[tail++]=st;
	dis[st]=0;
	while(front<tail){
		int cur=q[front++];
		if(cur==ed) return 1;
		for(int i=head[cur];i!=-1;i=e[i].nxt){
			if(e[i].w&&dis[e[i].v]<0){
				q[tail++]=e[i].v;
				dis[e[i].v]=dis[cur]+1;
			}
		}
	}
	if(dis[ed]==-1) return 0;
	return 1;
}
ll dfs(int cur,int lim){
	if(lim==0||cur==ed) return lim;
	ll w,flow=0;
	for(int i=head[cur];i!=-1;i=e[i].nxt){
		if(e[i].w&&dis[e[i].v]==dis[cur]+1){
			w=dfs(e[i].v,min(lim,e[i].w));
			e[i].w-=w;
			e[i^1].w+=w;
			flow+=w;
			lim-=w;
			if(lim==0) break;
		}
	}
	if(!flow) dis[cur]=-1;
	return flow;
}
ll dinic(){
	ll ans=0;
	while(bfs(st,ed)) 
		ans+=dfs(st,0x7fffffff);
	return ans;
}
int n,m,x,nx[4][2]={0,1,0,-1,1,0,-1,0};
ll sum=0;
int id(int x,int y){
	return (x-1)*m+y;
}
int main(){
	cin>>n>>m;
	ed=m*n+1;
	for(int i=0;i<=ed+10;i++) head[i]=-1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&x);sum+=x; 
			if((i+j)%2==1) 
			add(st,id(i,j),x);
			else 
			add(id(i,j),ed,x);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if((i+j)%2==1){
				for(int k=0;k<4;k++){
					int tx=i+nx[k][0];
					int ty=j+nx[k][1];
					if(tx<=0||ty<=0||tx>n||ty>m)continue;
					add(id(i,j),id(tx,ty),inf);
				}
			}
		}
	}
	sum-=dinic();
	printf("%lld\n",sum); 
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章