牛牛用卖烤串赚的钱买了一款游戏,这款游戏的地图是一个 n*n 的网格,其中有 m 个地区存在感染源(红色),其余地区为安全区(白色)。已知一个感染源可同时将与其相邻(上下左右)的安全区感染,被感染的安全区称之为新发地(黄色)。一个安全区变为一个新发地需要付出大小为 c 的代价。新发地可在下一时刻作为感染源将与其相邻的安全区感染为新的新发地。
为了遏制疫情扩散,牛牛决定采取下列两种措施
1. 在感染源(新发地)周围修建墙,墙可阻止疫情的扩散。但每堵墙需要付出大小为 1 的代价。
2. 任意让疫情扩散。
牛牛现在想知道采取哪种措施可以使得付出的代价最小。
思路
所有点向汇点连边流量是 表示被感染,然后本身被感染的点连向源点流量 INF 表示被感染。然后点和它四边之间连边流量是 表示要建护栏。
然后跑最小割就是答案。
# include <bits/stdc++.h>
using namespace std;
using ll= long long ;
const int INF= 0x3f3f3f3f ;
const int N= 4e5 + 5 , M= 4e5 + 5 ;
int n, m, c, s, t, k, head[ N] , nex[ M] , to[ M] , tot, mp[ 205 ] [ 205 ] ;
ll w[ M] , maxflow, deep[ N] ;
int now[ M] ;
queue< int > q;
inline void add ( int x, int y, int z) {
to[ tot] = y; w[ tot] = z; nex[ tot] = head[ x] ; head[ x] = tot ++ ;
to[ tot] = x; w[ tot] = 0 ; nex[ tot] = head[ y] ; head[ y] = tot ++ ;
}
inline bool bfs ( ) {
for ( int i = s; i <= t; ++ i)
deep[ i] = INF;
while ( ! q. empty ( ) ) q. pop ( ) ;
q. push ( s) ; deep[ s] = 0 ; now[ s] = head[ s] ;
while ( ! q. empty ( ) ) {
int x = q. front ( ) ; q. pop ( ) ;
for ( int i = head[ x] ; ~ i; i = nex[ i] ) {
int y = to[ i] ;
if ( w[ i] > 0 && deep[ y] == INF) {
q. push ( y) ;
now[ y] = head[ y] ;
deep[ y] = deep[ x] + 1 ;
if ( y == t) return 1 ;
}
}
}
return 0 ;
}
ll dfs ( int x, ll flow) {
if ( x == t) return flow;
ll ans = 0 , k, i;
for ( i = now[ x] ; ~ i && flow; i = nex[ i] ) {
now[ x] = i;
int y = to[ i] ;
if ( w[ i] > 0 && ( deep[ y] == deep[ x] + 1 ) ) {
k = dfs ( y, min ( flow, w[ i] ) ) ;
if ( ! k) deep[ y] = INF;
w[ i] -= k;
w[ i ^ 1 ] += k;
ans += k;
flow -= k;
}
}
return ans;
}
void dinic ( ) {
while ( bfs ( ) )
maxflow += dfs ( s, INF) ;
}
int get ( int x, int y) {
return ( x- 1 ) * n+ y;
}
int main ( ) {
scanf ( "%d%d%d" , & n, & m, & c) ;
memset ( head, - 1 , sizeof head) ;
s= 0 , t= n* n+ 1 ;
for ( int i= 1 , x, y, z; i<= m; i++ ) {
cin>> x>> y;
x++ , y++ ;
add ( s, get ( x, y) , INF) ;
}
for ( int i= 1 ; i<= n; i++ ) {
for ( int j= 1 ; j<= n; j++ ) {
add ( get ( i, j) , t, c) ;
if ( i!= n) add ( get ( i, j) , get ( i+ 1 , j) , 1 ) ;
if ( i!= 1 ) add ( get ( i, j) , get ( i- 1 , j) , 1 ) ;
if ( j!= n) add ( get ( i, j) , get ( i, j+ 1 ) , 1 ) ;
if ( j!= 1 ) add ( get ( i, j) , get ( i, j- 1 ) , 1 ) ;
}
}
dinic ( ) ;
printf ( "%lld\n" , maxflow- c* m) ;
return 0 ;
}