文理分科 洛谷4313 bzoj3894

题目描述

文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过)

小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式得到:

如果第i行第秒J的同学选择了文科,则他将获得art[i][j]的满意值,如果选择理科,将得到science[i][j]的满意值。

如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开心,所以会增加same_art[i][j]的满意值。

如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理科,则增加same_science[i][j]的满意值。

小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请告诉他这个最大值。

输入输出格式

输入格式:

第一行为两个正整数:n,m

接下来n行m个整数,表示art[i][j];

接下来n行m个整数.表示science[i][j];

接下来n行m个整数,表示same_art[i][j];

输出格式:

输出为一个整数,表示最大的满意值之和

思路

这里写图片描述
将所有收益累加减去最小割。

代码

#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=5e6+5,INF=0x3f3f3f3f;
const int xx[5]={0,1,0,-1,0},yy[5]={1,0,-1,0,0};
queue <int> Q;
long long ans;
int N,M,NM,S,T;
int dep[maxn],son[maxn],nxt[maxn],flw[maxn],lnk[maxn],tot;
int art[105][105],sci[105][105],sma[105][105],sms[105][105];
inline int read() {
    int ret=0,f=1;char ch=getchar();
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
    for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
    return ret*f;
}
inline bool can(int x,int y) {return x>=0&&x<y;}
inline void add_edge(int x,int y,int f) {
    son[tot]=y,flw[tot]=f,nxt[tot]=lnk[x],lnk[x]=tot++;
    son[tot]=x,flw[tot]=0,nxt[tot]=lnk[y],lnk[y]=tot++;
}
bool bfs() {
    memset(dep,0,sizeof dep);
    Q.push(S),dep[S]=1;
    while (!Q.empty()) {
        int u=Q.front();Q.pop();
        for (int k=lnk[u]; ~k; k=nxt[k]) if (dep[son[k]]==0&&flw[k]>0)
            dep[son[k]]=dep[u]+1,Q.push(son[k]);
    }
    return dep[T];
}
int dfs(int x,int flow) {
    if (x==T) return flow;
    int cnt=0;
    for (int k=lnk[x]; ~k; k=nxt[k]) if (dep[son[k]]==dep[x]+1&&flw[k]>0) {
        int d=dfs(son[k],min(flow,flw[k]));
        if (d<=0) continue;
        flw[k]-=d,flw[k^1]+=d,cnt+=d,flow-=d;
    }
    if (cnt==0) dep[x]=0;
    return cnt;
}
int main() {
    memset(lnk,-1,sizeof lnk);
    N=read(),M=read(),NM=N*M,S=NM*3+5,T=S+1;
    for (int i=0; i<N; i++) for (int j=0; j<M; j++) ans+=(art[i][j]=read());
    for (int i=0; i<N; i++) for (int j=0; j<M; j++) ans+=(sci[i][j]=read());
    for (int i=0; i<N; i++) for (int j=0; j<M; j++) ans+=(sma[i][j]=read());
    for (int i=0; i<N; i++) for (int j=0; j<M; j++) ans+=(sms[i][j]=read());
    for (int i=0; i<N; i++)
    for (int j=0; j<M; j++) {
        int id=i*M+j;
        add_edge(S,id,art[i][j]),add_edge(id,T,sci[i][j]);
        add_edge(S,id+NM,sma[i][j]),add_edge(id+NM+NM,T,sms[i][j]);
        for (int f=0; f<5; f++) if (can(i+xx[f],N)&&can(j+yy[f],M))
            add_edge(id+NM,(i+xx[f])*M+j+yy[f],INF),
            add_edge((i+xx[f])*M+j+yy[f],id+NM+NM,INF);
    }
    while (bfs()) ans-=dfs(S,INF);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ZJ_JS_ZXB/article/details/80853805