BZOJ3144[Hnoi2013]切糕——最小割
题目描述
输入
第一行是三个正整数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。
输出
仅包含一个整数,表示在合法基础上最小的总不和谐值。
样例输入
2 2 2
1
6 1
6 1
2 6
2 6
1
6 1
6 1
2 6
2 6
样例输出
6
提示
最佳切面的f为f(1,1)=f(2,1)=2,f(1,2)=f(2,2)=1
根据题意显然我们需要在二维平面的每个坐标上删除一个点。删除点不好办,我们将点转化成边:将第三维坐标为$z$的点变成连接第$z$层与第$z+1$层的边,即连接$(x,y,z)$与$(x,y,z+1)$,流量为$v(x,y,z)$,然后源点连向第一层的点,最后一层的点连向汇点。如果不考虑$D$的限制,直接按上述连边跑最小割即可。但现在考虑$D$的限制,我们将$(x,y,z)$连向$(x',y',z-D)$,流量为$INF$表示这条边不能被割。可以发现如果相邻两个坐标割的边第三维坐标差大于$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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> #define INF 1000000000 using namespace std; int head[70000]; int next[800000]; int to[800000]; int val[800000]; int d[70000]; int q[70000]; int n,m,r,D; int f[50][50][50]; int tot=1; int ans; int S,T; int dx[7]={0,1,0,-1}; int dy[7]={1,0,-1,0}; void add( int x, int y, int v) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; val[tot]=v; tot++; next[tot]=head[y]; head[y]=tot; to[tot]=x; val[tot]=0; } bool bfs( int S, int T) { int r=0; int l=0; memset (q,0, sizeof (q)); memset (d,-1, sizeof (d)); q[r++]=S; d[S]=0; while (l<r) { int now=q[l]; for ( int i=head[now];i;i=next[i]) { if (d[to[i]]==-1&&val[i]!=0) { d[to[i]]=d[now]+1; q[r++]=to[i]; } } l++; } return d[T]!=-1; } int dfs( int x, int flow) { if (x==T) { return flow; } int now_flow; int used=0; for ( int i=head[x];i;i=next[i]) { if (d[to[i]]==d[x]+1&&val[i]!=0) { now_flow=dfs(to[i],min(flow-used,val[i])); val[i]-=now_flow; val[i^1]+=now_flow; used+=now_flow; if (now_flow==flow) { return flow; } } } if (used==0) { d[x]=-1; } return used; } void dinic() { while (bfs(S,T)== true ) { ans+=dfs(S,0x3f3f3f); } } int calc( int x, int y, int z) { return y+(x-1)*m+(z-1)*n*m; } int main() { scanf ( "%d%d%d%d" ,&n,&m,&r,&D); S=n*m*(r+1)+1; T=S+1; for ( int k=1;k<=r;k++) { for ( int i=1;i<=n;i++) { for ( int j=1;j<=m;j++) { scanf ( "%d" ,&f[i][j][k]); } } } for ( int i=1;i<=n;i++) { for ( int j=1;j<=m;j++) { add(S,calc(i,j,1),INF); for ( int k=1;k<=r;k++) { add(calc(i,j,k),calc(i,j,k+1),f[i][j][k]); if (k<=D) { continue ; } for ( int s=0;s<4;s++) { int fx=dx[s]+i,fy=dy[s]+j; if (fx>=1&&fx<=n&&fy>=1&&fy<=m) { add(calc(i,j,k),calc(fx,fy,k-D),INF); } } } add(calc(i,j,r+1),T,INF); } } dinic(); printf ( "%d" ,ans); } |
分类:
网络流—最小割
【推荐】国内首个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应用必不可少的技术