1. 程式人生 > 實用技巧 >#網路流,dinic,最小割#P3227 [HNOI2013]切糕

#網路流,dinic,最小割#P3227 [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);
}