[BZOJ 3144] 切糕
Link:
Solution:
发现要把点集分成不连通的两部分,最小割的模型还是很明显的
首先我们将原图转化为$R+1$层,从而将点权化为边权
关键还是在于建图是怎么保证$|h_i-h_j|<=D$这个条件
要保证$|h_i-h_j|<=D$这个条件也就意味着选了$i$就不能选$j$,但仍然要保证$i->j$的连通性
于是我们由$i+D$向$i$连一条边权为$INF$的边,
这样如果割掉$i,j(j>i+D)$但不选择它们之间的边,就不会影响ST的连通性
只能再割掉$INF$边或其他边,这样两边同时选择明显不会计入答案
同时$i,j(j<=i+D)$就不会出现这样的问题,于是通过设置$INF$边就解决了这个问题
如上图,如果仅割掉右侧绿边和左侧红边,中间黑色的$INF$边仍会保持ST的连通性
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=50*50*50; const int INF=2147483647; int P,Q,R,D,S,T,id[50][50][50],iter[MAXN],level[MAXN],cnt=1,x; int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; struct edge { int to,cap,rev; }; vector<edge> G[MAXN]; void add_edge(int from,int to,int cap) { G[from].push_back(edge{to,cap,G[to].size()}); G[to].push_back(edge{from,0,G[from].size()-1}); } bool bfs() { memset(level,-1,sizeof(level)); queue<int> que;que.push(S);level[S]=0; while(!que.empty()) { int v=que.front();que.pop(); for(int i=0;i<G[v].size();i++) { edge &e=G[v][i]; if(e.cap && level[e.to]==-1) level[e.to]=level[v]+1,que.push(e.to); } } return (level[T]>0); } int dfs(int v,int f) { if(v==T) return f; for(int &i=iter[v];i<G[v].size();i++) { edge &e=G[v][i]; if(level[e.to]==level[v]+1 && e.cap) { int d=dfs(e.to,min(f,e.cap)); if(d) { e.cap-=d;G[e.to][e.rev].cap+=d; return d; } } } return 0; } int Dinic() { int ret=0; while(bfs()) { memset(iter,0,sizeof(iter)); int f; while((f=dfs(S,INF))>0) ret+=f; } return ret; } int main() { scanf("%d%d%d%d",&P,&Q,&R,&D); S=1; for(int i=1;i<=R+1;i++) for(int j=1;j<=P;j++) for(int k=1;k<=Q;k++) //预处理出编号 id[i][j][k]=++cnt; T=++cnt; for(int i=1;i<=R;i++) for(int j=1;j<=P;j++) for(int k=1;k<=Q;k++) scanf("%d",&x),add_edge(id[i][j][k],id[i+1][j][k],x); for(int i=1;i<=P;i++) for(int j=1;j<=Q;j++) add_edge(S,id[1][i][j],INF),add_edge(id[R+1][i][j],T,INF); for(int i=D+1;i<=R+1;i++) for(int j=1;j<=P;j++) for(int k=1;k<=Q;k++) for(int dir=0;dir<4;dir++) { int fx=j+dx[dir],fy=k+dy[dir]; if(!id[i-D][fx][fy]) continue; add_edge(id[i][j][k],id[i-D][fx][fy],INF); } printf("%d",Dinic()); return 0; }
Review:
1、认真审题,不要主观带入
这题一开始想成了切割线必须在同一个平面,还是不能读题时自己想当然啊
2、最小割模型的新套路
最小割的重点便在于割边计入答案
如果不想让两条边同时计入答案,可以在它们之间加入一条$INF$边,
保证同时选择两边时不会影响原图ST的连通性且$INF$边不会影响结果
使得同时选择两边时一定不符合最小的条件,从而不会计入答案
3、点权变边权
可以通过点变边,边变点的方式完成这样的转换