bzoj 3144: [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
Source
论学好语文的重要性,真的看不懂这个题目在说什么,这个人的切法真的是清新脱俗。。。
先把题目翻译一下:
有一个p*q的矩阵,每个位置上的格子上可以选r个数字中的一个填,每选一个数字都会有一个费用,并且相邻的格子上的数字相差不超过d,
求把每个格子填完数后的最小费用;
首先不考虑相差不超过d的限制,是一个经典的最小割模型:
每个点有n种选择,用s->x1->x2->x3->x4->T,如果割掉x1->x2的边,表示选择了x2,把图画出来的话很容易懂
然后考虑d的限制,用的是Inf限制不合法决策的方法(是最小割中常用技巧)
对于每个点加入选了k,那么该点的k向周围的点的k-d连Inf,周围点的k+d+1向该点的k+1连Inf的边,
把图画出来之后判断要如何割边才能使S-->T连通,可以把不合法的割边中增加Inf的流量从而使该决策不会被选为最小割中;
玄学剪枝真重要
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 | // MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #define RG register using namespace std; typedef long long ll; const int N=300050; const int Inf=19260817; int gi(){ int x=0,flag=1; char ch=getchar(); while (ch< '0' ||ch> '9' ){ if (ch== '-' ) flag=-1;ch=getchar();} while (ch>= '0' &&ch<= '9' ) x=x*10+ch- '0' ,ch=getchar(); return x*flag; } int id[50][50][50],f[50][50][50],p,q,r,d,tt,S,T; int mx[5]={1,-1,0,0},my[5]={0,0,1,-1}; int head[N],to[N],nxt[N],level[N],s[N],cnt=1,F,Q[N*5]; void Addedge( int x, int y, int z) { to[++cnt]=y,s[cnt]=z,nxt[cnt]=head[x],head[x]=cnt; } void lnk( int x, int y, int z){ Addedge(x,y,z),Addedge(y,x,0); } inline bool bfs(){ for (RG int i=S;i<=T;i++) level[i]=0; Q[0]=S,level[S]=1; int t=0,sum=1; while (t<sum){ int x=Q[t++]; if (x==T) return 1; for (RG int i=head[x];i;i=nxt[i]){ int y=to[i]; if (s[i]&&level[y]==0){ level[y]=level[x]+1; Q[sum++]=y; } } } return 0; } inline int dfs(RG int x, int maxf){ if (x==T) return maxf; int ret=0; for (RG int i=head[x];i;i=nxt[i]){ int y=to[i],f=s[i]; if (level[y]==level[x]+1&&f){ int minn=min(f,maxf-ret); f=dfs(y,minn); s[i]-=f,s[i^1]+=f,ret+=f; if (ret==maxf) break ; } } if (!ret) level[x]=0; return ret; } void Dinic(){ while (bfs()) F+=dfs(S,Inf); } int main(){ freopen( "cake.in" , "r" ,stdin); freopen( "cake.out" , "w" ,stdout); p=gi(),q=gi(),r=gi(),d=gi(); for ( int i=1;i<=r;i++) for ( int j=1;j<=p;j++) for ( int k=1;k<=q;k++){ f[j][k][i]=gi(),id[j][k][i]=++tt; } S=0,T=++tt; for ( int i=1;i<=p;i++) for ( int j=1;j<=q;j++){ lnk(S,id[i][j][1],f[i][j][1]); for ( int k=1;k<r;k++) lnk(id[i][j][k],id[i][j][k+1],f[i][j][k+1]); lnk(id[i][j][r],T,Inf); for ( int k=0;k<4;k++){ int x=i+mx[k],y=j+my[k]; if (1<=x&&x<=p&&1<=y&&y<=q){ for ( int z=1;z<=r;z++){ int zz=z-d,zzz=z+d+1; if (1<=zz&&zz<=r) lnk(id[i][j][z],id[x][y][zz],Inf); if (1<=zzz&&zzz<=r) lnk(id[x][y][zzz],id[i][j][z+1],Inf); } } } } Dinic();printf( "%d\n" ,F); return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步