【JZOJ 1919】happiness

Description

 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。
  作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

  第一行两个正整数n,m。
  接下来是六个矩阵
  第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。
  第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。
  第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。
  第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。
  第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。
  第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Solution

这题很显然的网络流,为Mike的农场的简化版
对于每个人,往S连一条文科喜悦值,向T连一条立刻喜悦值,
对于两者都选文科的情况,新建一个点,向S连一条值为喜悦值的边,再都向那两点连条无限的边,
对于两者都选理科的情况,跟上面差不多,改成向T连边即可,

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define H(i,j) ((i)*m-m+j)
using namespace std;
const int N=150*100*6,maxlongint=1047483640;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m,S,T,ans;
int A[N],B[6*N][3],B0=1;
int hv[N],h[N];
void link(int q,int w,int e1,int e2)
{
    B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w,B[B0][2]=e1;
    B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q,B[B0][2]=e2;
}
int aug(int q,int e)
{
    if(q==T)return e;
    int mi=T+1,E=e;
    efo(i,q)if(B[i][2])
    {
        int w=B[i][1];
        if(h[q]==h[w]+1)
        {
            int t=aug(w,min(e,B[i][2]));
            e-=t;
            B[i][2]-=t;
            B[i^1][2]+=t;
            if(!e||h[S]>T+1)return E-e;
        }
        mi=min(mi,h[w]);
    }
    if(E==e)
    {
        if(!(--hv[h[q]]))h[S]=T+2;
        hv[h[q]=mi+1]++;
    }
    return E-e;
}
int main()
{
    int q,w;
    read(n),read(m);
    S=0;T=n*m*5-2*m-2*n+1;ans=0;
    fo(i,1,n)fo(j,1,m)read(q),link(S,H(i,j),q,0),ans+=q;
    fo(i,1,n)fo(j,1,m)read(q),link(H(i,j),T,q,0),ans+=q;
    w=n*m;
    fo(i,1,n-1)fo(j,1,m)
        read(q),link(S,w+H(i,j),q,0),link(w+H(i,j),H(i,j),maxlongint,0),link(w+H(i,j),H(i+1,j),maxlongint,0),ans+=q;
    w+=(n-1)*m;
    fo(i,1,n-1)fo(j,1,m)
        read(q),link(T,w+H(i,j),0,q),link(w+H(i,j),H(i,j),0,maxlongint),link(w+H(i,j),H(i+1,j),0,maxlongint),ans+=q;
    w+=(n-1)*m;
    fo(i,1,n)
        fo(j,1,m-1)
        read(q),link(S,w+H(i,j)-i+1,q,0),link(w+H(i,j)-i+1,H(i,j),maxlongint,0),link(w+H(i,j)-i+1,H(i,j+1),maxlongint,0),ans+=q;
    w+=n*(m-1);
    fo(i,1,n)fo(j,1,m-1)
        read(q),link(T,w+H(i,j)-i+1,0,q),link(w+H(i,j)-i+1,H(i,j),0,maxlongint),link(w+H(i,j)-i+1,H(i,j+1),0,maxlongint),ans+=q;
    hv[0]=T+1;
    while(h[S]<T+2)ans-=aug(S,maxlongint);
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(网络流)