#網路流,dinic,最小割#P3227 [HNOI2013]切糕
阿新 • • 發佈:2020-08-06
題目大意
\(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); }