P4313 文理分科

题意简述

\(n \times m\)个座位,每个座位上的同学可以选择文科和理科。如果\((i,j)\)上的同学选文科,答案加\(art_{i,j}\),如果选理科,答案加\(sci_{i,j}\)。如果一个位置和其上、下、左、右(不包括没人的地方)都选文或理,则答案再加上\(sameart_{i,j}\)\(samesci_{i,j}\),求最大答案。

简单口胡

这题用最小割,因为这种两者选择的题目,显然是先把和求出来,在求出最小割减掉。
考虑建图,首先肯定是先连所有的\((S,(i,j),art_{i,j})\)\(((i,j),T,sci_{i,j})\)
然后\((S,(i,j),sameart_{i,j})\)\(((i,j),T,samesci_{i,j})\)
最小割转成最大流,没了。
难度主要在建边。

# include <bits/stdc++.h>

using namespace std;

const int N = 30100;
const int M = 240005;

int n,m;
int art[105][105];
int sci[105][105];
int same_art[105][105];
int same_sci[105][105];
int cur[N];

struct edge
{
    int u,v,w;
    int nxt;
    edge() {}
    edge(int _u,int _v,int _w) : u(_u),v(_v),w(_w) {}
}E[M << 1];

int Head[N];
int tot = 1;
int dep[N];

void add(int u,int v,int w)
{
    E[++tot] = edge(u,v,w);
    E[tot].nxt = Head[u];
    Head[u] = tot;
    E[++tot] = edge(v,u,0);
    E[tot].nxt = Head[v];
    Head[v] = tot;
    return;
}

int id(int x,int y)
{
    return (x - 1) * m + y;
}

int s,t;

bool bfs(void)
{
    memset(dep,0,sizeof(dep));
    dep[s] = 1;
    queue <int> q;
    q.push(s);
    while(!q.empty())
    {
        int x = q.front();q.pop();
        for(int i = Head[x]; i ; i = E[i].nxt)
        {
            int v = E[i].v;
            if(!dep[v] && E[i].w)
            {
                dep[v] = dep[x] + 1;
                q.push(v);
            }
        }
    }
    return dep[t] > 0;
}

int dfs(int x,int a)
{
    int sum = 0;
    if(x == t || a == 0) return a;
    for(int i = cur[x]; i ; i = E[i].nxt)
    {
        int v = E[i].v;
        if(dep[v] == dep[x] + 1 && E[i].w)
        {
            int tmp = dfs(v,min(a - sum,E[i].w));
            sum += tmp;
            E[i].w -= tmp;
            E[i xor 1].w += tmp;
        }
    }
    return sum;
}

int main(void)
{
    scanf("%d%d",&n,&m);
    int SUM = 0;
    s = 0,t = n * m + 1;
    int cnt = t;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d",&art[i][j]);
            add(s,id(i,j),art[i][j]);
            SUM += art[i][j];
        }
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d",&sci[i][j]);
            add(id(i,j),t,sci[i][j]);  
            SUM += sci[i][j];
        }
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d",&same_art[i][j]);
            ++cnt;
            add(s,cnt,same_art[i][j]);
            add(cnt,id(i,j),2e9 + 7);
            SUM += same_art[i][j];
            if(i - 1 >= 1) add(cnt,id(i - 1,j),2e9 + 7);
            if(i + 1 <= n) add(cnt,id(i + 1,j),2e9 + 7);
            if(j - 1 >= 1) add(cnt,id(i,j - 1),2e9 + 7);
            if(j + 1 <= m) add(cnt,id(i,j + 1),2e9 + 7);
        }
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d",&same_sci[i][j]);
            ++cnt;
            add(cnt,t,same_sci[i][j]);
            add(id(i,j),cnt,2e9 + 7);
            SUM += same_sci[i][j];
            if(i - 1 >= 1) add(id(i - 1,j),cnt,2e9 + 7);
            if(i + 1 <= n) add(id(i + 1,j),cnt,2e9 + 7);
            if(j - 1 >= 1) add(id(i,j - 1),cnt,2e9 + 7);
            if(j + 1 <= m) add(id(i,j + 1),cnt,2e9 + 7);
        }
    }
    int flow = 0;
    while(bfs()) 
    {
        for(int i = 0; i <= cnt; i++) cur[i] = Head[i];
        flow += dfs(s,2e9);
    }
    printf("%d\n",SUM - flow);
    return 0;
}
posted @ 2021-02-08 09:41  luyiming123  阅读(57)  评论(0编辑  收藏  举报