洛谷 P2774 方格取数问题 解题报告
主要说一下针对这种类型的题的思路:
- 首先算出最大得到的值,我们求最小割。
- 将网格图按照(行+列)的奇偶性分开,变成一个二分图
- 由奇点向偶点连边,走了一个不能走另一个的话,就连inf边(表示不可能割掉这条边)
- 具体细节根据题目分析
然后再来讲一下这道题:
同样非常的模板x.
- 记录一个ans,表示权值和。
- 我们对于每一个点,奇点就和s连边,偶点就和t连边,边容量=该点权值。
- 然后对于每一个奇点,向它四周的点连inf边(注意判定边界),表示这条边不能割,即这两个点与s/t的连边必须割去一个,也就是不能共存。
- 然后跑Dinic求出最小割,ans-maxflow就是答案。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #define ll long long #define space putchar(' ') #define endl putchar('\n') #define debug puts("------------------------") #define F(i,x,n) for(int i=x;i<=n;++i) #define F_(i,x,n) for(int i=x;i>=n;--i) using namespace std; inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; } inline int Rem() {int a=0,c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();return a*=b; } inline void write(int x) {if(x>9)write(x/10);putchar('0'+x%10);} inline void W(int x) {if(x<0){putchar('-'),x=-x;}write(x);} /**/ const int N=105*105,inf=0x3f3f3f3f; const int fx[]={0,0,1,-1},fy[]={1,-1,0,0}; int n,m,s,t,head[N],cnt=1,dep[N],cur[N]; ll maxflow,ans; bool vis[N]; struct edge { int nxt,to,c; }e[N*100]; /**/ namespace DINIC { inline void add_one(int u,int v,int c) { e[++cnt]=(edge){head[u],v,c}; head[u]=cnt; } inline void add(int u,int v,int c) { add_one(u,v,c); add_one(v,u,0); } inline bool bfs() { memset(dep,0x3f,sizeof(dep)); memset(vis,0,sizeof(vis)); memcpy(cur,head,sizeof(head)); vis[s]=1,dep[s]=0; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front();q.pop();vis[u]=0; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(dep[v]>dep[u]+1&&e[i].c) { dep[v]=dep[u]+1; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dep[t]!=inf; } int dfs(int u,int flow) { if(u==t) { vis[t]=1; maxflow+=flow; return flow; } int used=0,minflow=0; for(int i=cur[u];i;i=e[i].nxt) { cur[u]=i; int v=e[i].to; if(dep[v]==dep[u]+1&&e[i].c) { if((minflow=dfs(v,min(flow-used,e[i].c)))!=0) { used+=minflow; e[i].c-=minflow; e[i^1].c+=minflow; if(used==flow) break; } } } return used; } ll Dinic() { while(bfs()) { vis[t]=1; while(vis[t]) { vis[t]=0; dfs(s,inf); } } return maxflow; } }using namespace DINIC; int get(int x,int y) { return m*(x-1)+y; } int main() { read(n);read(m);s=n*m+1,t=s+1; for(int i=1,x;i<=n;i++) { for(int j=1;j<=m;j++) { read(x);ans+=x; if((i+j)&1) add(s,get(i,j),x); else add(get(i,j),t,x); } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if((i+j)&1) for(int k=0;k<4;k++) { int x=i+fx[k],y=j+fy[k]; if(x<1||y<1||x>n||y>m) continue; add(get(i,j),get(x,y),inf); } } } cout<<ans-Dinic(); }