- P2774 方格取数问题
- 把点权转换为了边权,我们的目的是断开一些边,使得没有路径从源点到达汇点(为了满足题目的条件)。
- 然后我们要使断开的边的权值之和最小(断开的边就相当于是不选那个点,就是剩下的边权之和最大)
- 所以我们可以跑一遍最大流求出最小割,然后用总的边权减去它就是我们的答案了
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 1134 int a[maxn][maxn],n,m,s,t,sum,ans; int head[maxn*maxn],cnt,level[maxn*maxn]; struct node { int to,v,w; } edge[maxn*maxn*4]; void add(int u,int v,int w) { edge[cnt].to=head[u]; edge[cnt].v=v; edge[cnt].w=w; head[u]=cnt++; edge[cnt].to=head[v]; edge[cnt].v=u; edge[cnt].w=0; head[v]=cnt++; } bool bfs() { memset(level,0,sizeof(level)); queue<int>q; q.push(s); level[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u]; i!=-1; i=edge[i].to) { int v=edge[i].v; if(!level[v]&&edge[i].w>0) { level[v]=level[u]+1; q.push(v); } } } return level[t]!=0; } int dfs(int u,int cp) { if(u==t)return cp; int addflow=0; for(int i=head[u]; i!=-1&&addflow<cp; i=edge[i].to) { int v=edge[i].v; if(level[u]+1==level[v]&&edge[i].w) { int temp=dfs(v,min(cp-addflow,edge[i].w)); edge[i].w-=temp; edge[i^1].w+=temp; addflow+=temp; } } return addflow; } void dinic() { int maxflow=0; while(bfs()) maxflow+=dfs(s,inf); ans=sum-maxflow; printf("%d\n",ans); } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&a[i][j]); s=0,t=n*m+m+1; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { sum+=a[i][j]; if((i+j)%2==0) { add(s,(i-1)*m+j,a[i][j]); if(i>1) add((i-1)*m+j,(i-2)*m+j,inf); if(j>1) add((i-1)*m+j,(i-1)*m+j-1,inf); if(i<n) add((i-1)*m+j,(i)*m+j,inf); if(j<m) add((i-1)*m+j,(i-1)*m+j+1,inf); } else add((i-1)*m+j,t,a[i][j]); } dinic(); return 0; }
P2774 方格取数问题-最小割模型
最新推荐文章于 2022-08-09 21:42:58 发布