博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 文理分科

题面

 

 

解析

首先,分析题目,

因为每个人要么选文科,要么选理科。

所以这道题可以用最小割来解决。

先设文科为S,理科为T(反过来也没区别),

再将每个人与文科,理科都连起来,

流量就为满意值,

那么,肯定得割掉一条边,

然后,就要处理相同科目满意值了,

其实,只要把相邻的四个人和中间的一个人连到一个点上,

再把那个点连到理科就行了(文科也一样但要另外建一个点)。

最后求最小割就可以了!

 

 

上AC代码:

#include<bits/stdc++.h>
using namespace std;

inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

const int INF=0x3f3f3f3f;
struct hh{
    int to,next,v;
}e[1000001];
int n,m,si,ti,sum;
int a[101][101],s[101][101],sa[101][101],ss[101][101];
int id[101][101];
int head[100001],cnt=1;
int d[100001];
int dx[4]={0,0,1,-1};
int dy[4]={-1,1,0,0};

void ppre(){
    int kk=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) id[i][j]=++kk;
}

void add(int x,int y,int v){
    e[++cnt].to=head[x];
    e[cnt].next=y;
    e[cnt].v=v;
    head[x]=cnt;
}

bool bfs(){
    memset(d,0,sizeof(d));
    queue <int> que;
    que.push(si);
    d[si]=1;
    while(!que.empty()){
        int x=que.front();
        que.pop();   
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;
            if(!e[i].v||d[k]) continue;
            d[k]=d[x]+1;        
            que.push(k);
        }
    }
    return d[ti];
}

int dfs(int x,int mi){
    if(x==ti||!mi) return mi;
    int flow=0;
    for(int i=head[x];i;i=e[i].to){
        int k=e[i].next;
        if(!e[i].v||d[k]!=d[x]+1) continue;
        int ret=dfs(k,min(mi,e[i].v));
        e[i].v-=ret;e[i^1].v+=ret;
        flow+=ret;mi-=ret;
        if(!mi) break;
    }
    if(mi) d[x]=-1;
    return flow;
}

void DINIC(){
    int ans=sum;
    while(bfs()){
        int ret=dfs(si,INF);
        sum-=ret;
    }
    printf("%d\n",sum);
}

int main(){
//    freopen("divide.in","r",stdin);    
//    freopen("divide.out","w",stdout);
    n=read();m=read();
        ppre();
    si=n*m*3+10;ti=n*m*3+20;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read(),sum+=a[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s[i][j]=read(),sum+=s[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            sa[i][j]=read(),sum+=sa[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ss[i][j]=read(),sum+=ss[i][j];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            add(si,id[i][j],s[i][j]);
            add(id[i][j],si,0);
            add(id[i][j],ti,a[i][j]);
            add(ti,id[i][j],0);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int l=id[i][j]+n*m;
            add(l,ti,sa[i][j]);add(ti,l,0);
            add(id[i][j],l,INF);add(l,id[i][j],0);
            for(int k=0;k<4;k++){
                int x=i+dx[k],y=j+dy[k];
                if(x<=0||y<=0||x>n||y>m) continue;
                add(id[x][y],l,INF);add(l,id[x][y],0);
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int l=id[i][j]+n*m*2;
            add(si,l,ss[i][j]);add(l,si,0);
            add(l,id[i][j],INF);add(id[i][j],l,0);
//            add(id[i][j],l,INF);add(l,id[i][j],0);
            for(int k=0;k<4;k++){
                int x=i+dx[k],y=j+dy[k];
                if(x<=0||y<=0||x>n||y>m) continue;
                add(l,id[x][y],INF);add(id[x][y],l,0);
            }
        }
    }
    DINIC();
    return 0;
    
}

 

posted @ 2019-03-14 09:58  Hastin  阅读(229)  评论(0编辑  收藏  举报