zoukankan      html  css  js  c++  java
  • 【BZOJ3144】[HNOI2013]切糕

    【BZOJ3144】[HNOI2013]切糕

    题面

    题目描述

    经过千辛万苦小 A 得到了一块切糕,切糕的形状是长方体,小 A 打算拦腰将切糕切成两半分给小 B。出于美观考虑,小 A 希望切面能尽量光滑且和谐。于是她找到你,希望你能帮她找出最好的切割方案。

    出于简便考虑,我们将切糕视作一个长 P、宽 Q、高 R 的长方体点阵。我们将位于第 z层中第 x 行、第 y 列上(1≤x≤P, 1≤y≤Q, 1≤z≤R)的点称为(x,y,z),它有一个非负的不和谐值 v(x,y,z)。一个合法的切面满足以
    下两个条件:
    1.与每个纵轴(一共有 P*Q 个纵轴)有且仅有一个交点。即切面是一个函数 f(x,y),对于所有 1≤x≤P, 1≤y≤Q,我们需指定一个切割点 f(x,y),且 1≤f(x,y)≤R。

    2.切面需要满足一定的光滑性要求,即相邻纵轴上的切割点不能相距太远。对于所有的 1≤x,x’≤P 和 1≤y,y’≤Q,若|x-x’|+|y-y’|=1,则|f(x,y)-f(x’,y’)| ≤D,其中 D 是给定的一个非负整数。 可能有许多切面f 满足上面
    的条件,小A 希望找出总的切割点上的不和谐值最小的那个。

    输入格式

    第一行是三个正整数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

    题解

    注意题目第一句话:

    经过千辛万苦小 A 得到了一块切糕

    说到千辛万苦,我就想起了师徒四人去取经,今年下半年

    中美,合拍,文体,开花 谢谢!!!

    23333333


    Q:当我们没有那个光滑度限制时怎么做呢?

    A:每一个纵轴取max

    A:往上新建一层(R+1)(S)连向第一层每个点的容量为(infty)的边,第(R+1)层每个点向(T)连容量为(infty)的边,对于(forall 1leq kleq R),每个((i,j,k))((i,j,k+1))连容量为(v_{i,j,k})的边,再求最小割即可。

    接下来考虑有光滑度限制的情况:

    我们的限制条件是:

    (|x-i|+|y-j|=1)(f(x,y)-f(i,j)leq D)

    实际上就是要求(f(x,y)-f(i,j)>D)时,(S)可以到达(T)

    那么直接由距离为(1)的两个点((x,y),(i,j))

    对于(forall D+1leq kleq R+1),连((i,j,k-D) ightarrow(x,y,k)(cap=infty))

    最后跑最小割即可

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <queue> 
    using namespace std; 
    const int MAX_N = 50;
    const int MAX_V = MAX_N * MAX_N * MAX_N;
    const int INF = 1e9; 
    struct Graph { int to, cap, next; } e[MAX_V << 2]; int fir[MAX_V], e_cnt, V; 
    void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; } 
    void Add_Edge(int u, int v, int c) { 
        e[e_cnt] = (Graph){v, c, fir[u]}, fir[u] = e_cnt++; 
        e[e_cnt] = (Graph){u, 0, fir[v]}, fir[v] = e_cnt++; 
    } 
    int level[MAX_V], iter[MAX_V]; 
    void bfs(int s) { 
        static queue<int> que; fill(&level[0], &level[V + 1], -1); 
        que.push(s), level[s] = 0; 
        while (!que.empty()) { 
            int x = que.front(); que.pop(); 
            for (int i = fir[x]; ~i; i = e[i].next) {
                int v = e[i].to;
                if (level[v] == -1 && e[i].cap > 0) level[v] = level[x] + 1, que.push(v); 
            } 
        } 
    } 
    int dfs(int x, int t, int f) { 
        if (x == t || !f) return f; 
        for (int &i = iter[x]; ~i; i = e[i].next) { 
            int v = e[i].to; 
            if (e[i].cap > 0 && level[v] > level[x]) {
                int d = dfs(v, t, min(f, e[i].cap)); 
                if (d != 0) {
                    e[i].cap -= d;
                    e[i ^ 1].cap += d;
                    return d; 
                } else level[v] = -1; 
            } 
        } 
        return 0; 
    } 
    int max_flow(int s, int t) {
        int flow = 0;
        for (;;) { 
            bfs(s); 
            if (level[t] == -1) return flow;
            int f;
            for (int i = 0; i <= V; i++) iter[i] = fir[i]; 
            while ((f = dfs(s, t, INF))) flow += f; 
        } 
    } 
    int P, Q, R, D, a[MAX_N][MAX_N][MAX_N]; 
    const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1}; 
    int main () {
    	clearGraph(); 
    	scanf("%d%d%d%d", &P, &Q, &R, &D);
    	for (int k = 1; k <= R; k++) 
    		for (int i = 1; i <= P; i++) 
    			for (int j = 1; j <= Q; j++) 
    				scanf("%d", &a[i][j][k]); 
    	int s = 0, t = P * Q * (R + 1) + 1; V = t; 
    	for (int i = 1; i <= P; i++)
    		for (int j = 1; j <= Q; j++) { 
            int x = (i - 1) * Q + j + 1; 
            Add_Edge(s, x, INF); 
    		for (int k = 1; k <= R; k++) Add_Edge(P * Q * (k - 1) + x, P * Q * k + x, a[i][j][k]); 
            Add_Edge(P * Q * R + x, t, INF); 
        } 
        for (int i = 1; i <= P; i++)
    		for (int j = 1; j <= Q; j++) 
                for (int h = 0; h < 4; h++) { 
    				int x = i + dx[h], y = j + dy[h]; 
    				if (x < 1 || x > P || y < 1 || y > Q) continue; 
    				for (int k = D + 1; k <= R + 1; k++) 
    					Add_Edge(P * Q * (k - 1) + (i - 1) * Q + j + 1, P * Q * (k - D - 1) + (x - 1) * Q + y + 1, INF); 
                }
    	printf("%d
    ", max_flow(s, t)); 
    	return 0; 
    } 
    
  • 相关阅读:
    Mvc的路由
    Java编程思想——第14章 类型信息(一)RTTI
    让你的sql开启氮气加速
    CountDownLatch和CycliBarrier介绍
    Java编程思想——第21章 并发
    emojy表情的小问题
    ThreadPoolExecutor使用方法
    Java8两大特性(一)——Stream
    js保留两位小数(不四舍五入)
    vant popup能不能插在body下
  • 原文地址:https://www.cnblogs.com/heyujun/p/10290562.html
Copyright © 2011-2022 走看看