BZOJ 3144 [HNOI2013]切糕 (最大流+巧妙的建图)

题面:洛谷传送门 BZOJ传送门

最大流神题

把点权转化为边权,切糕里每个点$(i,j,k)$向$(i,j,k+1)$连一条流量为$v(i,j,k)$的边

源点$S$向第$1$层的点连边,第$R+1$层的点向$T$连边,流量均为$inf$

跑最大流,最大流的流量就是答案

因为每条纵轴都取了最小的$v$,被割掉的边就是最小的$v$所在的边

然而题目里还有限制,相邻两个纵轴取值的位置相差的距离不能超过$D$

如何处理这个限制呢?

每个点$(i,j,k)$向$(x,y,k-D)$连流量为$inf$的边,$(x,y)$是$(i,j)$相邻的纵轴

假设纵轴$(i,j)$的割点是$(i,j,k)$

如果$(x,y)$的割点在$(x,y,k-D)$下面,一定会有一条流量从纵轴$(i,j)$流到$(x,y)$里,然后向上流到汇点$T$

巧妙地解决了距离的限制问题

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N1 67010
 5 #define M1 400010
 6 #define L1 45
 7 using namespace std;
 8 const int inf=0x3f3f3f3f;
 9  
10 int gint()
11 {
12     int ret=0,fh=1;char c=getchar();
13     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
14     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
15     return ret*fh;
16 }
17 struct Edge{
18 int to[M1<<1],nxt[M1<<1],flow[M1<<1],head[N1],cte;
19 void ae(int u,int v,int f)
20 {
21     cte++; to[cte]=v; nxt[cte]=head[u];
22     head[u]=cte; flow[cte]=f; 
23 }
24 }e;
25  
26 int dep[N1],que[M1],cur[N1],n,m,h,D,hd,tl,S,T;
27 int bfs()
28 {
29     int x,j,v;
30     memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur));
31     hd=1,tl=0; que[++tl]=S; dep[S]=0;
32     while(hd<=tl)
33     {
34         x=que[hd++];
35         for(j=e.head[x];j;j=e.nxt[j])
36         {
37             v=e.to[j];
38             if( dep[v]==-1 && e.flow[j]>0 )
39             {
40                 dep[v]=dep[x]+1;
41                 que[++tl]=v;
42             }
43         }
44     }
45     return dep[T]!=-1;
46 }
47 int dfs(int x,int limit)
48 {
49     int j,v,flow,ans=0;
50     if(!limit||x==T) return limit;
51     for(j=cur[x];j;j=e.nxt[j])
52     {
53         v=e.to[j]; cur[x]=j;
54         if( dep[v]==dep[x]+1 && (flow=dfs(v,min(limit,e.flow[j]))) )
55         {
56             e.flow[j]-=flow; limit-=flow;
57             e.flow[j^1]+=flow; ans+=flow;
58             if(!limit) break;
59         }
60     }
61     return ans;
62 }
63 int Dinic()
64 {
65     int mxflow=0,j,v,ans=0;
66     while(bfs())
67         mxflow+=dfs(S,inf);
68     return mxflow;
69 }
70  
71 int xx[4]={-1,0,1,0},yy[4]={0,1,0,-1};
72 int v[L1][L1][L1],id[L1][L1][L1];
73 inline int check(int x,int y){return (x<1||y<1||x>n||y>m)?0:1;}
74  
75 int main()
76 {
77     scanf("%d%d%d%d",&n,&m,&h,&D);
78     int i,j,k,x,y,w,p; e.cte=1; S=0; T=n*m*(h+1)+1;
79     for(k=1;k<=h+1;k++) for(i=1;i<=n;i++) for(j=1;j<=m;j++) id[k][i][j]=(k-1)*n*m+(i-1)*m+j;
80     for(k=1;k<=h;k++) for(i=1;i<=n;i++) for(j=1;j<=m;j++) 
81     {
82         w=v[k][i][j]=gint(), x=id[k][i][j];
83         e.ae(x,x+n*m,w), e.ae(x+n*m,x,0);
84         if(k<=D) continue;
85         //x+=n*m;
86         for(p=0;p<4;p++)
87         {
88             if(!check(i+xx[p],j+yy[p])) continue;
89             y=id[k-D][i+xx[p]][j+yy[p]];
90             e.ae(x,y,inf); e.ae(y,x,0);
91         }
92     }
93     for(i=1;i<=n;i++) for(j=1;j<=m;j++) e.ae(S,id[1][i][j],inf), e.ae(id[1][i][j],S,0);
94     for(i=1;i<=n;i++) for(j=1;j<=m;j++) e.ae(id[h+1][i][j],T,inf), e.ae(T,id[h+1][i][j],0);
95     printf("%d\n",Dinic());
96     return 0;
97 }

 

posted @ 2019-02-03 14:04  guapisolo  阅读(194)  评论(0编辑  收藏  举报