题意
三维空间10*10*10方块,一些方块坏掉了,求用最少的面包裹住坏掉的方块,可以同时包裹好的方块。其中面只能处于方块间隙中。
题解
典型的最小割问题。以每个方块为点,S与最外围所有点连边,其中在顶点处的点连3边,不在顶点且在棱上的点连2边,其他点连1边。好点与周围六个方向点连1边,坏点与T连inf边,求最小割即可。
代码
/****************************************\
* Author : ztx
* Title : C - Containment
* ALG : 网络流-最小割
* CMT : 能割的地方连流量为1的边,
S与最外围所有点连1边,黑色点之间连inf边,黑色点与T连inf边,求最小割
* Time :
\****************************************/
#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
while (ret=getchar() , ret<'!') ;
while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
ret[0]=0;while (CH=getchar() , CH<'!') ;
while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
ret[ret[0]+1]=0;
}
#include <cstring>
#define maxn 15LL
#define maxN 10000LL
#define maxM 100000LL
#define infi 0x3f3f3f3fLL
struct FST { int to , next , flow ; } e[maxM<<1] ;
int star[maxN] , tote ;
inline void FST_init() { memset(star , 0 , sizeof star) ; tote = 1 ; }
inline void AddEdge(int u , int v , int cap) {
e[++tote].to = v ; e[tote].flow = cap ; e[tote].next = star[u] ; star[u] = tote ;
e[++tote].to = u ; e[tote].flow = 0 ; e[tote].next = star[v] ; star[v] = tote ;
}
#define min(x,y) ((x)<(y)?(x):(y))
int N , S , T ;
int h[maxN] , vh[maxN] ;
int dfs(int u , int flowu) {
int p , tmp = h[u]+1 ;
int flow = 0 , flowv ;
if (u == T) return flowu ;
for (p = star[u] ; p ; p = e[p].next) {
if (e[p].flow && (h[e[p].to]+1==h[u])) {
flowv = dfs(e[p].to , min(flowu-flow , e[p].flow)) ;
flow += flowv ; e[p].flow -= flowv ; e[p^1].flow += flowv ;
if (flow==flowu || h[S]==N) return flow ;
}
}
for (p = star[u] ; p ; p = e[p].next)
if (e[p].flow) tmp = min(tmp , h[e[p].to]) ;
if (--vh[h[u]] == 0) h[S] = N ;
else ++ vh[h[u]=tmp+1] ;
return flow ;
}
int SAP() {
int ret = 0 ;
memset(vh , 0 , sizeof vh) ;
memset(h , 0 , sizeof h) ;
vh[S] = N ;
while (h[S] < N) ret += dfs(S , infi) ;
return ret ;
}
bool g[maxn][maxn][maxn] ;
int f[maxn][maxn][maxn] ;
const int dx[6] = {0,0,1,-1,0,0} ;
const int dy[6] = {0,0,0,0,1,-1} ;
const int dz[6] = {1,-1,0,0,0,0} ;
int main() {
int Time , i , j , k , ii , jj , kk , dir , m ;
// #define READ
#ifdef READ
freopen(".in" ,"r",stdin ) ;
freopen(".out","w",stdout) ;
#endif
N = 0 ;
Rep (i,1,10) Rep (j,1,10) Rep (k,1,10)
f[i][j][k] = ++N ;
S = ++N , T = ++N ;
for (read(Time) ; Time -- ; ) {
read(m) ;
memset(g,0,sizeof g) ;
FST_init() ;
Rep (i,1,m) {
read(ii) , read(jj) , read(kk) ; // 0->9 ==> 1->10
g[ii+1][jj+1][kk+1] = 1 ;
}
Rep (i,1,10) Rep (j,1,10) Rep (k,1,10) {
dir = 0 ;
if (i==1||i==10) dir ++ ;
if (j==1||j==10) dir ++ ;
if (k==1||k==10) dir ++ ;
if (dir) AddEdge(S,f[i][j][k],dir) ;
if (g[i][j][k]) AddEdge(f[i][j][k],T,infi) ;
else {
rep (dir,0,6) {
ii = i+dx[dir] ;
jj = j+dy[dir] ;
kk = k+dz[dir] ;
if (ii>0&&ii<11&&jj>0&&jj<11&&kk>0&&kk<11) {
AddEdge(f[i][j][k],f[ii][jj][kk],1) ;
}
}
}
}
printf("%d\n", SAP()) ;
}
#ifdef READ
fclose(stdin) ; fclose(stdout) ;
#else
getchar() ; getchar() ;
#endif
return 0 ;
}