BZOJ3144【HNOI2013】切糕

来源:互联网 发布:msdb数据库下载 编辑:程序博客网 时间:2024/04/25 07:59

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3144


【分析】

    所有人都说这是个经典的最小割模型......蒟蒻泪流满面......

    建一个r+1层的,每层都是p*q的图,从源出发向第一层连inf的边,从第r+1层上每个点出发向汇连inf的边,对i,j,k与i,j,k+1之间连v(i,j,k)的边。

    如果没有高度限制,那么这么做就是在每一条纵轴上选一个点。

    因为有高度限制,所以对于每个层数大于d的点,要向x,y坐标相邻的,层数小d的点连一条inf的边。

    以p=1,q=2,r=5,d=2为例。(先忽略从右边较高的点连向左边较低的点的那些边)

    

    下面是源,上面是汇。如图所示,如果我把图中的红边割掉,那么图中的蓝边也就没有用了。如果此时把绿边割掉,那么还是存在一条从源到汇的路径;如果割绿色的边上面的边,那么源到汇就没有路径可达了。

    仔细理解一下,也就是在左边选了一条边以后,右边的高度小于当前边的边就不能选了。如果把右上向左下连的边也连起来,那么高度就完全限制住了。

    然后跑一下最大流就好了。


【代码】

#include <cstdio>#include <algorithm>using namespace std;const int maxl=45,maxn=75000,maxm=maxn<<4,inf=~0U>>1,mov[4][2]={{0,1},{1,0},{0,-1},{-1,0}};int head[maxn],next[maxm],E[maxm],F[maxm],Ecnt;int id[maxl][maxl][maxl];int p,q,r,d;int s,e;inline void Add_Edge(int x,int y,int f) {next[++Ecnt]=head[x];head[x]=Ecnt;E[Ecnt]=y;F[Ecnt]=0;next[++Ecnt]=head[y];head[y]=Ecnt;E[Ecnt]=x;F[Ecnt]=f;}void Init(){scanf("%d%d%d%d",&p,&q,&r,&d);int cnt=0,x;Ecnt=1;s=++cnt;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;e=++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],e,inf);#define nx (j+mov[mv][0])#define ny (k+mov[mv][1])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 mv=0;mv<4;mv++)if (id[i][nx][ny])Add_Edge(id[i][j][k],id[i-d][nx][ny],inf);#undef nx#undef ny}int Q[maxn],Vis[maxn],h[maxn];bool BFS(int time){int top=1,tail=1;Q[1]=s;Vis[1]=time;h[1]=0;while (top<=tail){int x=Q[top++],hx=h[x];for (int i=head[x];i;i=next[i]) if (Vis[E[i]]!=time && F[i^1])h[E[i]]=h[x]+1,Vis[E[i]]=time,Q[++tail]=E[i];if (Vis[e]==time) break;}return Vis[e]==time;}int DFS(int x,int f){if (x==e) return f;int res=f;for (int i=head[x];i && res;i=next[i]) if (h[E[i]]==h[x]+1 && F[i^1]){int d=DFS(E[i],min(F[i^1],res));res-=d;F[i]+=d;F[i^1]-=d;}if (f==res) h[x]=-1;return f-res;}void Dinic(){int res=0,time=0;while (BFS(++time)) res+=DFS(s,inf);printf("%d\n",res);}int main(){Init();Dinic();return 0;}


0 0
原创粉丝点击