1 条题解
-
0
自动搬运
来自洛谷,原作者为

NewSjf
**搬运于
2025-08-24 21:32:05,当前版本为作者最后更新于2019-11-11 20:28:03,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
好像下面的题解都是双向边
我是虚拟点做的,这样感觉也挺好理解的
思路其实都差不多,实现上略微有点差别
首先我们先看P1361 小M的作物
参考那道题的题解,可以抽象出这么一个模型
具体的解释可以参考那道题题解
然后我们回到这道题,这道题和那道题的不同之处就在于那道题两个元素在同一个集合就会有附加权值,而这道题是两个元素不在同一个集合才会有负价权值,现在就看如何转换
我用了一种十分傻瓜的方式
首先我们考虑黑白染色

我们发现白色位置的附加权值取决于四个相邻黑色位置的选择,黑色亦然
这里不用去交换源汇点 直接把其中一种颜色的A和B权值交换就行了
这样两个位置本来要选择不一样才会有附加权值
现在变成了两个位置集合相同才会有附加权值
于是这道题被完美的转化成了P1361
和那道题做法一模一样
建虚拟点,跑dinic,得答案#include<iostream> #include<algorithm> #include<cstring> #include<queue> #define INF 252645135 #define MAXN 1001 using namespace std; struct side{int from,to,next,w;}edge[MAXN*MAXN]; int cur[MAXN*MAXN],head[MAXN*MAXN],depth[MAXN*MAXN],N,M,n,s,t,len=-1; int A[MAXN][MAXN],B[MAXN][MAXN],C[MAXN][MAXN]; int dx[]={0,0,1,-1},dy[]={1,-1,0,0},sum; void __add_edge(int x,int y,int d){edge[++len]=(side){x,y,head[x],d};head[x]=len;} void add_edge(int x,int y,int d) { __add_edge(x,y,d); __add_edge(y,x,0); } int bfs() { queue<int>q; for(int i=0;i<=n;i++)depth[i]=0,cur[i]=head[i]; q.push(s);depth[s]=1; while(q.size()) { int now=q.front();q.pop(); for(int k=head[now];k!=-1;k=edge[k].next) if(edge[k].w>0&&depth[edge[k].to]==0) depth[edge[k].to]=depth[now]+1, q.push(edge[k].to); } return depth[t]!=0; } int dfs(int now,int flow) { if(now==t)return flow; for(int&k=cur[now];k!=-1;k=edge[k].next) if(edge[k].w>0&&depth[edge[k].to]==depth[now]+1) { int minflow=dfs(edge[k].to,min(flow,edge[k].w)); if(minflow>0) { edge[k].w-=minflow; edge[k^1].w+=minflow; return minflow; } } return 0; } int dinic(int ans=0) { while(bfs()) while(int flow=dfs(s,INF))ans+=flow; return ans; } int point(int x,int y) { return (x-1)*M+y; } int main() { memset(head,-1,sizeof(head)); cin>>N>>M; n=N*M; s=++n; t=++n; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) cin>>A[i][j],sum+=A[i][j]; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) cin>>B[i][j],sum+=B[i][j]; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) cin>>C[i][j]; for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) if((i+j)%2==1)swap(A[i][j],B[i][j]); //翻转 for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { add_edge(s,point(i,j),A[i][j]); add_edge(point(i,j),t,B[i][j]); } for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) { for(int k=0;k<4;k++) { int nx=i+dx[k],ny=j+dy[k]; if(0<nx&&nx<=N&&0<ny&&ny<=M) { int x=++n; int y=++n; sum+=2*C[i][j]; add_edge(s,x,C[i][j]); add_edge(x,point(i,j),INF); add_edge(x,point(nx,ny),INF); add_edge(y,t,C[i][j]); add_edge(point(i,j),y,INF); add_edge(point(nx,ny),y,INF); } } } cout<<sum-dinic(); }希望大家有所收获
- 1
信息
- ID
- 902
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者