題目背景
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;
}