【LOJ】#2384. 「HNOI2013」切糕

题解

神仙网络流啊……

naive的我一直想把每个纵轴拆点,每个纵轴建R个点(大概是要跑费用流吧……)……然后第二个限制就gg了,什么也想不出来,菜啊TAT

后来我发现大神们的建图都是,一个原点,一个汇点,一段长条,每一段就是一个点,流量是值,那么最小割就是最小值了,很神奇

然后每相邻的两个纵轴z向z - D连一条边,z再向z + D连一条边

感觉很神奇,后来我想了一下,这样并不能保证割了z之后一定割了相邻的[z - D,z+D]的点,而是可以保证,如果割错了这个割一定会被换掉!错误的答案是有限的,重复的错误不会出现……所以,最后就是正确的答案了呗。。。

最小割保证了答案最小

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 70005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
struct node {
    int to,next,cap;
}E[4000005];
int head[MAXN],sumE = 1,S,T,last[MAXN],Ncnt;
int dis[MAXN],gap[MAXN],P,Q,R,D;
int val[45][45][45],MK[45][45][45];
int dx[] = {0,-1};
int dy[] = {-1,0};
void add(int u,int v,int c) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    E[sumE].cap = c;
    head[u] = sumE;
}
void addtwo(int u,int v,int c) {
    add(u,v,c);add(v,u,0);
}
int sap(int u,int aug) {
    if(u == T) return aug;
    int flow = 0;
    for(int i = last[u] ; i ; last[u] = i = E[i].next) {
    int v = E[i].to;
    if(E[i].cap) {
        if(dis[v] + 1 == dis[u]) {
        int t = sap(v,min(aug - flow,E[i].cap));
        flow += t;
        E[i].cap -= t;
        E[i ^ 1].cap += t;
        if(flow == aug) return flow;
        if(dis[S] >= T) return flow;
        }
    }
    }
    --gap[dis[u]];if(!gap[dis[u]]) dis[S] = T;
    ++gap[++dis[u]];last[u] = head[u];
    return flow;
}
void Solve() {
    read(P);read(Q);read(R);
    read(D);
    for(int i = 1 ; i <= R ; ++i) {
    for(int j = 1 ; j <= P ; ++j) {
        for(int k = 1 ; k <= Q ; ++k) {
        read(val[j][k][i]);
        }
    }
    }
    S = ++Ncnt;
    T = P * Q * (R + 1) + 10;
    for(int i = 1 ; i <= P ; ++i) {
    for(int j = 1 ; j <= Q ; ++j) {
        ++Ncnt;addtwo(S,Ncnt,0x7fffffff);
        for(int k = 1 ; k <= R; ++k) {
        ++Ncnt;
        MK[i][j][k] = Ncnt;
        addtwo(Ncnt - 1,Ncnt,val[i][j][k]);
        }
        addtwo(Ncnt,T,0x7fffffff);
    }
    }
    for(int i = 1 ; i <= P ; ++i) {
    for(int j = 1 ; j <= Q ; ++j) {
        for(int h = 0 ; h <= 1 ; ++h) {
        int tx = i + dx[h],ty = j + dy[h];
        if(tx <= 0 || ty <= 0) continue;
        for(int k = 1 ; k <= R ; ++k) {
            if(k - D >= 1) addtwo(MK[i][j][k],MK[tx][ty][k - D],0x7fffffff);
            if(k + D <= R) addtwo(MK[tx][ty][k + D],MK[i][j][k],0x7fffffff);
        }
        }
    }
    }
    for(int i = 1 ; i <= T ; ++i) last[i] = head[i];
    int ans = 0;
    while(dis[S] < T) ans += sap(S,0x7fffffff);
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

猜你喜欢

转载自www.cnblogs.com/ivorysi/p/9176008.html