传送门:hdu1565 方格取数(1)
传送门:hdu1569 方格取数(2)
定理:
1. 最小点权覆盖集=最小割=最大流
2. 最大点权独立集=总权-最小点权覆盖集
步骤:
1. 先染色,取一个点染白色,和它相邻的点染黑色
2. 每个白点向它相邻的黑点连一条边,容量为 inf (无穷大)
3. 增加源点S,向每一个白色点连一条边,容量为白点的权
4. 增加汇点T,每个黑点向T连一条边,容量为黑点的权
#pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <limits.h> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 100000000 #define inf 0x3f3f3f3f #define eps 1e-6 #define N 2510 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define PII pair<int,int> using namespace std; inline int read() { char ch=getchar(); int x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,vs,vt,tot,NV; int head[N],gap[N],level[N],q[N]; struct edge { int v,w,next; edge(){} edge(int v,int w,int next):v(v),w(w),next(next){} }e[N*N]; void addedge(int u,int v,int w) { e[tot]=edge(v,w,head[u]); head[u]=tot++; e[tot]=edge(u,0,head[v]); head[v]=tot++; } void init() { memset(head,-1,sizeof(head)); tot=0; } /***************************SAP***********************/ void bfs(int vt) { memset(level,-1,sizeof(level)); memset(gap,0,sizeof(gap)); level[vt]=0; gap[level[vt]]++; queue<int>que; que.push(vt); while(!que.empty()) { int u=que.front(); que.pop(); for(int i=head[u]; i!=-1; i=e[i].next) { int v=e[i].v; if(level[v]!=-1)continue; level[v]=level[u]+1; gap[level[v]]++; que.push(v); } } } int pre[N]; int cur[N]; int SAP() { bfs(vt); memset(pre,-1,sizeof(pre)); memcpy(cur,head,sizeof(head)); int u=pre[vs]=vs,flow=0,aug=inf; gap[0]=NV; while(level[vs]<NV) { bool flag=false; for(int &i=cur[u]; i!=-1; i=e[i].next) { int v=e[i].v; if(e[i].w&&level[u]==level[v]+1) { flag=true; pre[v]=u; u=v; aug=min(aug,e[i].w); if(v==vt) { flow+=aug; for(u=pre[v]; v!=vs; v=u,u=pre[u]) { e[cur[u]].w-=aug; e[cur[u]^1].w+=aug; } aug=inf; } break; } } if(flag)continue; int minlevel=NV; for(int i=head[u]; i!=-1; i=e[i].next) { int v=e[i].v; if(e[i].w&&level[v]<minlevel) { minlevel=level[v]; cur[u]=i; } } if(--gap[level[u]]==0)break; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } return flow; } /**************************SAP**********************/ int sum,x,num[55][55],id[55][55]; bool judge(int i,int j) { return i>=1&&i<=n&&j>=1&&j<=m; } void build() { sum=x=0;NV=n*m+2; vs=0;vt=n*m+1; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { x++; num[i][j]=read(); sum+=num[i][j]; id[i][j]=x; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if((i+j)&1) { addedge(id[i][j],vt,num[i][j]); } else { addedge(vs,id[i][j],num[i][j]); for(int x=-1;x<=1;x++) for(int y=-1;y<=1;y++) { if(x+y==0||x==y||!judge(x+i,y+j))continue; addedge(id[i][j],id[i+x][j+y],inf); } } } } } int main() { while(scanf("%d%d",&n,&m)>0) { init(); build(); printf("%d ",sum-SAP()); } }