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 }
深深地明白自己的弱小