#网络流,dinic,最小割#洛谷 3227 [HNOI2013]切糕

题目传送门


题目大意

\(P\)\(Q\)列的楼房高度均为\(R\),每一层改造要花费一定的金钱,
每个楼房都要挑选有且仅有一层进行改造,并且相邻两个楼房改造位置的相对高度不能超过\(D\)
问最小花费


分析

原题目更能看出是最小割,但是这样题意更能懂一些,
可以建一个分层图,建一个虚拟层,这样把点换为边,
接着源点连第一层,虚拟层连汇点,容量无穷大
但是相对高度怎么搞,就是让它割不掉嘛
若两个点\((x_1,y_1),(x_2,y_2)\)相邻,
那么\((x_1,y_1,k)\)\((x_2,y_2,k+D)\)连一条边,容量无穷大,就好了


代码

#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
const int inf=1e7,N=66011;
struct node{int y,w,next;}e[N*11];
const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int ls[N],dis[N],P,Q,R,D,ans,s,t,k=1; bool v[N];
inline signed iut(){
    rr int ans=0,f=1; rr char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans*f;
}
inline void add(int x,int y,int w){
	e[++k]=(node){y,w,ls[x]}; ls[x]=k;
	e[++k]=(node){x,0,ls[y]}; ls[y]=k;
}
inline signed bfs(int s){
    for (rr int i=1;i<=t;++i) dis[i]=0;
    queue<int>q; q.push(s); dis[s]=1;
    while (q.size()){
        rr int x=q.front(); q.pop();
        for (rr int i=ls[x];i;i=e[i].next)
        if (e[i].w>0&&!dis[e[i].y]){
            dis[e[i].y]=dis[x]+1;
            if (e[i].y==t) return 1;
            q.push(e[i].y);
        }
    }
    return 0;
}
inline signed dfs(int x,int now){
    if (x==t||!now) return now;
    rr int rest=0,f;
    for (rr int i=ls[x];i;i=e[i].next)
    if (e[i].w>0&&dis[e[i].y]==dis[x]+1){
        rest+=(f=dfs(e[i].y,min(now-rest,e[i].w)));
        e[i].w-=f; e[i^1].w+=f;
        if (now==rest) return rest;
    }
    if (!rest) dis[x]=0;
    return rest;
}
signed main(){
    P=iut(),Q=iut(),R=iut(),
    D=iut(),s=P*Q*(R+1)+1,t=s+1;
    for (rr int i=1;i<=R;++i)
    for (rr int j=1;j<=P;++j)
    for (rr int k=1;k<=Q;++k)
        add((i*P+j-P-1)*Q+k,(i*P+j-1)*Q+k,iut());
    for (rr int i=1;i<=P;++i)
    for (rr int j=1;j<=Q;++j)
        add(s,(i-1)*Q+j,inf),add((R*P+i-1)*Q+j,t,inf);
    for (rr int i=1;i<=P;++i)
    for (rr int j=1;j<=Q;++j)
    for (rr int u=0;u<4;++u){
        rr int x=i+dx[u],y=j+dy[u];
        if (x<1||x>P||y<1||y>Q) continue;
        for (rr int h=D;h<=R;++h)
        add((h*P+i-1)*Q+j,(h*P-D*P+x-1)*Q+y,inf);
    }
    while (bfs(s)) ans+=dfs(s,inf);
    return !printf("%d",ans);
}
posted @ 2020-08-06 20:43  lemondinosaur  阅读(83)  评论(0编辑  收藏  举报