bzoj3144: [Hnoi2013]切糕(最小割)

传送门

 

据说这玩意儿叫切糕模型?

我们可以看做有$P*Q$个网格,每个格子有$R$个点,在每一个格子中选一个点,且相邻的点距离不能超过$d$,求最小代价

考虑如果没有限制条件怎么做。我们可以把每一个网格中的点都串成一条链,每一条边容量为该点的权值,如果一条边被割代表这个点被选,然后都连上源点和汇点,那么跑一个最小割就行了

然后有了限制条件怎么做呢?我们令每一个点都向相邻的点连边,即令$(i,j,k)$向$(i',j',k-d)$连边,容量$inf$。那么,假设我们会选的点的距离超过了$d$,那么就意味着在原图中割掉的边的距离超过$d$,但因为每对距离为$d$的点间都连了容量为$inf$的边,所以仍然能够到达,那么这就不是一个最小割。

具体我讲不太来,可以画一个图比较好理解

 1 // luogu-judger-enable-o2
 2 //minamoto
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<queue>
 7 #define inf 0x3f3f3f3f
 8 using namespace std;
 9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
10 char buf[1<<21],*p1=buf,*p2=buf;
11 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
12 inline int read(){
13     #define num ch-'0'
14     char ch;bool flag=0;int res;
15     while(!isdigit(ch=getc()))
16     (ch=='-')&&(flag=true);
17     for(res=num;isdigit(ch=getc());res=res*10+num);
18     (flag)&&(res=-res);
19     #undef num
20     return res;
21 }
22 const int N=100005,M=1000005;
23 int head[N],Next[M],ver[M],edge[M],tot=1;
24 int dep[N],cur[N],n,m,s,t,h,d;
25 queue<int> q;
26 inline void add(int u,int v,int e){
27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
28     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0;
29 }
30 bool bfs(){
31     while(!q.empty()) q.pop();
32     memset(dep,-1,sizeof(dep));
33     for(int i=s;i<=t;++i) cur[i]=head[i];
34     q.push(s),dep[s]=0;
35     while(!q.empty()){
36         int u=q.front();q.pop();
37         for(int i=head[u];i;i=Next[i]){
38             int v=ver[i];
39             if(dep[v]<0&&edge[i]){
40                 dep[v]=dep[u]+1,q.push(v);
41                 if(v==t) return true;
42             }
43         }
44     }
45     return false;
46 }
47 int dfs(int u,int limit){
48     if(u==t||!limit) return limit;
49     int flow=0,f;
50     for(int i=cur[u];i;i=Next[i]){
51         int v=ver[i];cur[u]=i;
52         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
53             flow+=f,limit-=f;
54             edge[i]-=f,edge[i^1]+=f;
55             if(!limit) break;
56         }
57     }
58     if(!flow) dep[u]=-1;
59     return flow;
60 }
61 int dinic(){
62     int flow=0;
63     while(bfs()) flow+=dfs(s,inf);
64     return flow;
65 }
66 #define id(i,j,k) (((i-1)*m+j-1)*h+k)
67 int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
68 int main(){
69     //freopen("testdata.in","r",stdin);
70     n=read(),m=read(),h=read(),d=read();
71     s=0,t=n*m*h+1;
72     for(int k=1;k<=h;++k)
73     for(int i=1;i<=n;++i)
74     for(int j=1;j<=m;++j){
75         int x=read();
76         if(k==1) add(s,id(i,j,k),x);
77         else add(id(i,j,k-1),id(i,j,k),x);
78         if(k==h) add(id(i,j,k),t,inf);
79     }
80     for(int i=1;i<=n;++i)
81     for(int j=1;j<=m;++j)
82     for(int k=d+1;k<=h;++k)
83     for(int l=0;l<4;++l){
84         int x=i+dx[l],y=j+dy[l];
85         if(x>=1&&x<=n&&y>=1&&y<=m) add(id(i,j,k),id(x,y,k-d),inf);
86     }
87     printf("%d\n",dinic());
88     return 0;
89 }

 

posted @ 2018-08-31 15:24  bztMinamoto  阅读(188)  评论(0编辑  收藏  举报
Live2D