BZOJ3144: [Hnoi2013]切糕
Description
Input
第一行是三个正整数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。
Output
仅包含一个整数,表示在合法基础上最小的总不和谐值。
Sample Input
2 2 2
1
6 1
6 1
2 6
2 6
1
6 1
6 1
2 6
2 6
Sample Output
6
HINT
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1
考虑用最小割来做,我们可以这样建图:
对于每一个格子(i,j),将S向(i,j,1)连条容量为A[i][j][1]的边,将(i,j,r)向T连条容量为inf的边,(i,j,k-1)向(i,j,k)连一条容量为A[i][j][k]的边。
那么这条链上的割就代表选了一个f(i,j)。
如果加上D的限制,考虑两个相邻格子(i,j)和(i`,j`),从(i,j,k+D)向(i`,j`,k)连一条容量为inf的边,从(i`,j`,k+D)向(i,j,k)连一条容量为inf的边,意为如果f[i][j]选了k+D,那么f[i`][j`]肯定要>=k,且如果f[i`][j`]选了k+D,那么f[i][j]肯定要>=k,解出f[i`][j`]-D<=f[i][j]<=f[i`][j`]+D且f[i][j]-D<=f[i`][j`]<=f[i][j]+D,恰好满足题意。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if (head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1; char c=Getchar(); for (;!isdigit(c);c=Getchar()) if (c== '-' ) f=-1; for (;isdigit(c);c=Getchar()) x=x*10+c- '0' ; return x*f; } const int maxn=70010; const int maxm=1000010; struct Dinic { int n,m,s,t,clo; int first[maxn],next[maxm]; int cur[maxn],vis[maxn],d[maxn]; struct Edge { int from ,to,flow;}edges[maxm]; void init( int n) { this ->n=n;m=0; memset(first,-1, sizeof (first)); } void AddEdge( int u, int v, int w) { edges[m]=(Edge){v,u,0};next[m]=first[v];first[v]=m++; edges[m]=(Edge){u,v,w};next[m]=first[u];first[u]=m++; } int Q[maxn]; int BFS() { int l=1,r=1;Q[r++]=s;vis[s]=++clo; while (l!=r) { int x=Q[l++];cur[x]=first[x]; ren { Edge& e=edges[i]; if (e.flow&&vis[e.to]!=clo) { vis[e.to]=clo; d[e.to]=d[x]+1; Q[r++]=e.to; } } } return vis[t]==clo; } int DFS( int x, int a) { if (x==t||!a) return a; int flow=0,f; for ( int & i=cur[x];i!=-1;i=next[i]) { Edge& e=edges[i]; if (d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.flow)))) { e.flow-=f;edges[i^1].flow+=f; flow+=f;a-=f; if (!a) break ; } } return flow; } int solve( int s, int t) { this ->s=s; this ->t=t; int flow=0; while (BFS()) flow+=DFS(s,1e9); return flow; } }sol; int n,m,r,d,A[45][45][45]; int id( int i, int j, int k) { return (k-1)*n*m+(i-1)*m+j;} const int mx[]={1,-1,0,0}; const int my[]={0,0,1,-1}; int main() { n=read();m=read();r=read();d=read(); int S=n*m*r+1,T=n*m*r+2;sol.init(T); rep(i,1,r) rep(j,1,n) rep(k,1,m) A[j][k][i]=read(); rep(i,1,n) rep(j,1,m) rep(k,1,r) { if (k==1) sol.AddEdge(S,id(i,j,k),A[i][j][k]); else sol.AddEdge(id(i,j,k-1),id(i,j,k),A[i][j][k]); if (k==r) sol.AddEdge(id(i,j,k),T,1e9); if (k>d) rep(dir,0,3) { int nx=i+mx[dir],ny=j+my[dir]; if (nx>=1&&nx<=n&&ny>=1&&ny<=m) sol.AddEdge(id(i,j,k),id(nx,ny,k-d),1e9); } } printf( "%d\n" ,sol.solve(S,T)); return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术