• BZOJ3144 [Hnoi2013]切糕 【最小割】


    题目

    这里写图片描述

    输入格式

    第一行是三个正整数P,Q,R,表示切糕的长P、 宽Q、高R。第二行有一个非负整数D,表示光滑性要求。接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R)。
    100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000。

    输出格式

    仅包含一个整数,表示在合法基础上最小的总不和谐值。

    输入样例

    2 2 2

    1

    6 1

    6 1

    2 6

    2 6

    输出样例

    6

    提示

    最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1

    题解

    论一类最小割模型:

    有P * Q个纵列,每列选一个点,且相邻纵列之间的点距离不超过D,求选点最小值

    我们将每一列所有点向其下一个点连边【这时候多加上额外的一层点】,容量为其权值,这样由最小割,每一类都会选择一条边割去,就意味着选了这条边入度的点
    这里写图片描述

    为了满足相邻距离不超过D的限制,我们对(x,y,z)向相邻的(x’,y’,z - D)连边INF,使得在选择(x,y,z)后必须选择(x’,y’,z - D)以上的点,如图
    这里写图片描述

    如此建图,跑最大流

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
    #define cls(x) memset(x,0,sizeof(x))
    #define p(x,y,z) ((z - 1) * P * Q + (x - 1) * Q + y)
    using namespace std;
    const int maxn = 100000,maxm = 3000005,INF = 1000000000;
    inline int RD(){
        int out = 0,flag = 1; char c = getchar();
        while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
        while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
        return out * flag;
    }
    int P,Q,R,D;
    int h[maxn],ne = 0,cur[maxn],d[maxn],vis[maxn],S,T;
    struct EDGE{int to,f,nxt;}ed[maxm];
    inline void build(int u,int v,int w){
        ed[ne] = (EDGE){v,w,h[u]}; h[u] = ne++;
        ed[ne] = (EDGE){u,0,h[v]}; h[v] = ne++;
    }
    bool bfs(){
        for (int i = S; i <= T; i++) vis[i] = d[i] = 0;
        queue<int> q;
        d[S] = 0; vis[S] = true; q.push(S); int u,to;
        while (!q.empty()){
            u = q.front(); q.pop();
            Redge(u) if (ed[k].f && !vis[to = ed[k].to]){
                d[to] = d[u] + 1; vis[to] = true; q.push(to);
            }
        }
        return vis[T];
    }
    int dfs(int u,int minf){
        if (u == T || !minf) return minf;
        int flow = 0,f,to;
        if (cur[u] == -2) cur[u] = h[u];
        for (int& k = cur[u]; k != -1; k = ed[k].nxt)
            if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){
                ed[k].f -= f; ed[k ^ 1].f += f;
                minf -= f; flow += f;
                if (!minf) break;
            }
        return flow;
    }
    int maxflow(){
        int flow = 0;
        while (bfs()){
            for (int i = S; i <= T; i++) cur[i] = -2;
            flow += dfs(S,INF);
        }
        return flow;
    }
    int X[4] = {0,0,-1,1},Y[4] = {-1,1,0,0};
    int main(){
        memset(h,-1,sizeof(h));
        P = RD(); Q = RD(); R = RD(); D = RD(); S = 0; T = P * Q * (R + 1) + 1;
        int v;
        REP(x,P) REP(y,Q) build(S,p(x,y,1),INF),build(p(x,y,R + 1),T,INF);
        REP(z,R) REP(x,P) REP(y,Q){
            v = RD();
            build(p(x,y,z),p(x,y,z + 1),v);
            if (z - D > 0){
                for (int k = 0; k < 4; k++){
                    int nx = x + X[k],ny = y + Y[k];
                    if (nx < 1 || ny < 1 || nx > P || ny > Q) continue;
                    build(p(x,y,z),p(nx,ny,z - D),INF);
                }
            }
        }
        printf("%d",maxflow());
        return 0;
    }
    
  • 相关阅读:
    Oil Deposits UVA
    工作区的颜值选择(中等)
    计算机网络 自定向下方法1.1-1.2
    工作区的颜值选择(简单)
    排序算法之简单选择排序
    排序算法之直接插入排序
    查找算法之查找一个数组中只出现过一次的数
    查找算法之查找一个数组中两两数字相同,只有其中两个数字是不一样的,将其找出
    Linux
    ASP.NET Web – 状态管理
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282695.html
Copyright © 2020-2023  润新知