核心思想:在最小割中用容量為無窮大的邊來表示限制。
這題相當於一個 p∗q p*q的矩陣,每個矩陣添一個 [0,r] [0,r]的數,且相鄰數之差不超過 d d,同時最小化 v(i,j,k) v(i,j,k)。
先把一個格子的取值串起來,就是 (i,j,k) (i,j,k)向 (i,j,k+1) (i,j,k+1)連一條容量為 v(i,j,k+1) v(i,j,k+1)的邊;
特別地, S S向 (i,j,1) (i,j,1)連一條容量為 (i,j,1) (i,j,1)的邊, (i,j,r) (i,j,r)向T連一條容量為無窮大的邊;
那麼這些邊中必須割一條,表示填的數是什麼。
然後考慮差不超過d的限制,就是 (i,j,k) (i,j,k)向 (i−1,j,k−d) (i-1,j,k-d)、 (i+1,j,k−d) (i+1,j,k-d)、 (i,j−1,k−d) (i,j-1,k-d)、 (i,j+1,k−d) (i,j+1,k-d)連一條容量為無窮大的邊。
這樣就保證不能同時割 (i,j,≥k) (i,j,\ge k)和 (相鄰的,≤k−d) (相鄰的,\le k-d);因為每串最多割一條邊。
代碼:
#include<iostream>#include<cstdio>#include<cstring> #define G(x,y,z) (((x-1)*m+y-1)*r+z-1)using namespace std;int n,m,r,d,v[45][45][45],S,T,dl[64010],ne[64010];bool vis[64010];struct edge{ int t,c,f; edge *next,*rev;}*con[64010];void ins(int x,int y,int c){ edge *p=new edge;p->t=y;p->c=c;p->f=0;p->next=con[x];con[x]=p; p=new edge;p->t=x;p->c=0;p->f=0;p->next=con[y];con[y]=p; con[x]->rev=con[y];con[y]->rev=con[x];}bool bfs(){ bool re=0; memset(ne,0,sizeof(ne)); ne[S]=1;dl[1]=S; for(int head=1,tail=1;head<=tail;head++) { int v=dl[head]; if(v==T) re=1; for(edge *p=con[v];p;p=p->next) if(p->c>p->f&&ne[p->t]==0) ne[p->t]=ne[v]+1,dl[++tail]=p->t; } return re;}int dinic(int v,int fl