#网络流#洛谷 4313 文理分科
题目传送门
分析
显然是网络流,答案为正边权和减去最小割
但怎么建图,首先源点与汇点分别连自身文理满意值
考虑文理都必须拆点,文科先和源点连一条边,再与相邻连INF
理科先和汇点连一条边,再与相邻连INF
这样文科理科二者不可得兼,最大流=最小割,那么就可以用网络流求
代码
#include <cstdio>
#include <cctype>
#include <queue>
#define ide(i,j) ((i-1)*m+j)
#define rr register
using namespace std;
const int dx[5]={0,1,0,-1,0},dy[5]={1,0,-1,0,0};
struct node{int y,w,next;}e[550011]; const int inf=707406378;
int dis[30011],ls[30011],n,m,k=1,ans,s,t;
inline signed iut(){
rr int ans=0,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans*f;
}
inline void add(int x,int y,int w){
e[++k]=(node){y,w,ls[x]}; ls[x]=k;
e[++k]=(node){x,0,ls[y]}; ls[y]=k;
}
inline signed bfs(int s){
for (rr int i=1;i<=t;++i) dis[i]=0;
rr queue<int>q; q.push(s); dis[s]=1;
while (q.size()){
rr int x=q.front(); q.pop();
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].w>0&&!dis[e[i].y]){
dis[e[i].y]=dis[x]+1;
if (e[i].y==t) return 1;
q.push(e[i].y);
}
}
return 0;
}
inline signed dfs(int x,int now){
if (x==t||!now) return now;
rr int rest=0,f;
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
rest+=(f=dfs(e[i].y,min(now-rest,e[i].w)));
e[i].w-=f; e[i^1].w+=f;
if (now==rest) return rest;
}
if (!rest) dis[x]=0;
return rest;
}
signed main(){
n=iut(),m=iut(),s=3*n*m+1,t=s+1;
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j) add(s,ide(i,j),iut());
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j) add(ide(i,j),t,iut());
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j) add(s,ide(i,j)+n*m,iut());
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j) add(ide(i,j)+2*n*m,t,iut());
for (rr int i=2;i<=k;i+=2) ans+=e[i].w;
for (rr int i=1;i<=n;++i)
for (rr int j=1;j<=m;++j)
for (rr int k=0;k<5;++k){
rr int x=i+dx[k],y=j+dy[k];
if (x<1||x>n||y<1||y>m) continue;
add(ide(i,j)+n*m,ide(x,y),inf);
add(ide(i,j),ide(x,y)+2*n*m,inf);
}
while (bfs(s)) ans-=dfs(s,inf);
return !printf("%d",ans);
}