#网络流#洛谷 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);
}
posted @ 2020-02-23 23:39  lemondinosaur  阅读(195)  评论(0编辑  收藏  举报