1. 程式人生 > >洛谷 P2774 方格取數問題

洛谷 P2774 方格取數問題

解題思路 -m targe urn front 思路 || 運行 取數

題目背景

none!

題目描述

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

輸入輸出格式

輸入格式:

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

輸出格式:

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

輸入輸出樣例

輸入樣例#1:
3 3
1 2 3
3 2 3
2 3 1 
輸出樣例#1:
11

說明

none!

解題思路

  一道和騎士共存問題差不多的題目,二分圖黑白染色後跑最大獨立集,這裏每個白格向四周連邊,而不是馬能攻擊到的地方(廢話)。

源代碼

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>


int n,m;
int a[1000][1000]={0};
int S=0;
inline int id(int x,int y)
{
    return (x-1)*m+y;
}

int s,t;
struct Edge{ int next,to,flow; }e[1000010]; int cnt=2,head[1000]={0}; void add(int u,int v,int f) { e[cnt]={head[u],v,f}; head[u]=cnt++; e[cnt]={head[v],u,0}; head[v]=cnt++; } int dis[1000]={0}; bool bfs() { memset(dis,0,sizeof(dis)); std::queue<int> q; q.push(s); dis[s]
=1; while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(dis[v]||!e[i].flow) continue; dis[v]=dis[u]+1; q.push(v); } } return dis[t]!=0; } int dfs(int u,int f) { if(u==t||f==0) return f; int flow_sum=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(dis[v]!=dis[u]+1||!e[i].flow) continue; int temp=dfs(v,std::min(e[i].flow,f-flow_sum)); e[i].flow-=temp; e[i^1].flow+=temp; flow_sum+=temp; if(flow_sum>=f) break; } if(!flow_sum) dis[u]=-1; return flow_sum; } int dinic() { int ans=0; while(bfs()) { while(int temp=dfs(s,0x7fffffff)) ans+=temp; } return ans; } int main() { scanf("%d%d",&n,&m); s=n*m+1,t=s+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]),S+=a[i][j]; int bh[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if((i+j)&1) { add(s,id(i,j),a[i][j]); for(int k=0;k<4;k++) { int x=i+bh[k][0],y=j+bh[k][1]; if(x>=1&&x<=n&&y>=1&&y<=m) add(id(i,j),id(x,y),0x7fffffff); } } else add(id(i,j),t,a[i][j]); } } printf("%d\n",S-dinic()); return 0; }

洛谷 P2774 方格取數問題