题意描述

sol :
考虑如何转化问题。假设我把所有的收益都加起来,减去最少的收益就是答案。
原问题 = 总收益 - 最小割
- 文理不能同时选
考虑对于每个点 i , s 向 i 连一条容量为 art[i] 的 有向边 , i 向 t 也连一条容量为 sci[i] 的边,这样 art[i] 和 sci[i] 必须断一条。
- 对于每个点,要考虑它和上下左右同文同理时的贡献
对于同文点,记作 i2 ,从 s 向 i2 连一条容量为 same_art[i] 的边,i2 再向包括它自己的相邻点连一条容量为 inf 的边。
对于同理点,记作 i3 ,从 i3 向 t 连一条容量为 same_sci[i] 的边,再从包括它自己的相邻边向它连一条容量为 inf 的边

我们来证明它为什么是正确的。
显然文理边至少会断一个,而对于一个点的同文或同理不能同时存在(否则存在一条流量大于 0 的路径)。对于文理边同时断掉的情况,如果断掉的是同文,就把理边恢复;如果断掉的是同理,就把文边恢复,此时同样是割。
证明完毕。
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=105*105*3;
const int M=1e6+5;
int n,m,s,t,rt,a[4][N],id[3][N],res;
int lab[N],que[N],cur[N];
int tot,head[M],nxt[M],to[M],cap[M];
int dx[5]={-1,0,1,0},dy[5]={0,1,0,-1};
void add(int u,int v,int w) {
tot++;
nxt[tot]=head[u],head[u]=tot,to[tot]=v,cap[tot]=w;
}
bool BFS() {
for(int i=0;i<=rt;i++) lab[i]=0;
lab[t]=1;
int qhead=0,qtail=0;
que[qtail++]=t;
while(qhead!=qtail) {
int u=que[qhead++];
for(int k=head[u];k;k=nxt[k]) {
int v=to[k];
if(cap[k^1]==0||lab[v]>0) {
continue;
}
lab[v]=lab[u]+1;
que[qtail++]=v;
}
}
return lab[s]!=0;
}
int flow(int u,int limit) {
if(u==t) {
return limit;
}
int used=0;
for(int k=cur[u];k;k=nxt[k]) {
int v=to[k];
cur[u]=k;
if(lab[u]!=lab[v]+1||cap[k]==0) {
continue;
}
int tmp=min(limit-used,cap[k]);
int ret=flow(v,tmp);
used+=ret;
cap[k]-=ret;
cap[k^1]+=ret;
if(ret==0||cap[k]==0) {
cur[u]=nxt[k];
}
if(limit==used) break;
}
return used;
}
int has(int i,int j) {
return (i-1)*m+j;
}
bool outside(int x,int y) {
if(x<1||x>n||y<1||y>m) return 1;
return 0;
}
int dinic() {
int tot=0;
while(BFS()) {
for(int i=0;i<=rt;i++) cur[i]=head[i];
tot+=flow(s,INF);
}
return tot;
}
int main() {
tot=1;
for(int i=0;i<=rt;i++) {
head[i]=0;
}
s=rt=0;
scanf("%d%d",&n,&m);
for(int k=0;k<4;k++) {
for(int i=1;i<=n*m;i++) {
scanf("%d",&a[k][i]);
res+=a[k][i];
}
}
for(int k=0;k<3;k++) {
for(int i=1;i<=n*m;i++) {
id[k][i]=++rt;
}
}
t=++rt;
for(int i=1;i<=n*m;i++) {
add(s,id[0][i],a[0][i]);
add(id[0][i],s,0);
add(id[0][i],t,a[1][i]);
add(t,id[0][i],0);
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
int u=id[1][has(i,j)];
int f=has(i,j);
add(s,u,a[2][f]);
add(u,s,0);
for(int k=0;k<5;k++) {
int ti=i+dx[k],tj=j+dy[k];
if(outside(ti,tj)) continue;
int v=id[0][has(ti,tj)];
add(u,v,INF);
add(v,u,0);
}
u=id[2][has(i,j)];
add(u,t,a[3][f]);
add(t,u,0);
for(int k=0;k<5;k++) {
int ti=i+dx[k],tj=j+dy[k];
if(outside(ti,tj)) continue;
int v=id[0][has(ti,tj)];
add(v,u,INF);
add(u,v,0);
}
}
}
printf("%d",res-dinic());
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」