POJ 2227 The Wedding Juicer FloodFill算法
这题看了以后,想了一个很脑残的做法,也过了,不过用了1.2s,哈哈。
后来看了一个高中生大牛写的 Pascal 程序。
根据函数名字来看,它用的是 floodfill 算法,提交了发现居然才用了188ms。
现在高中生真太牛逼了!佩服!
同时,作为一个即将毕业的大学生,哥表示压力很大。。
以前没见过这个算法,看了一下,发现看不大懂,但是这样做确实很有道理!
在网上面搜了一下关于floodfill算法的资料,发现很杂,还是看不大懂。。
算法的思想就是:
每个点都有一个水位,水位最小值为这个点的高度。
首先把边缘一周的点加入堆,这些点的水位初始化为点的高度。
每次都取出最小水位的点,将点周围的四个点里面,从来没有被加入过堆的点加入堆中,如果有的点的高度比水位低,那么就更新答案。
删除最小水位的点,然后重复上一步。直到不存在没有被加入过堆中的点为止。
用 C 再写了一遍,小小改动,慢了 100ms。
#include
<
stdio.h
>
#define SIZE 332
struct heap_node {
int x, y;
} ;
int W, H;
int map[SIZE][SIZE], fil[SIZE][SIZE];
struct heap_node heap[SIZE * SIZE];
int heap_size, left, ans;
inline int cmp( struct heap_node * a, struct heap_node * b)
{
return fil[a->y][a->x] - fil[b->y][b->x];
}
inline void shift_down( int idx)
{
struct heap_node val = heap[idx];
while (1) {
idx *= 2;
if (idx > heap_size)
break;
if (idx + 1 <= heap_size && cmp(&heap[idx + 1], &heap[idx]) < 0)
idx++;
if (cmp(&val, &heap[idx]) <= 0)
break;
heap[idx / 2] = heap[idx];
}
heap[idx / 2] = val;
}
inline void shift_up( int idx)
{
struct heap_node val = heap[idx];
while (1) {
if (idx / 2 <= 0)
break;
if (cmp(&heap[idx / 2], &val) <= 0)
break;
heap[idx] = heap[idx / 2];
idx /= 2;
}
heap[idx] = val;
}
inline void insert( int y, int x, int f = - 1 )
{
if (y < 0 || y >= H || x < 0 || x >= W || fil[y][x])
return ;
if (map[y][x] > f)
f = map[y][x];
else
ans += f - map[y][x];
fil[y][x] = f;
heap_size++;
heap[heap_size].y = y;
heap[heap_size].x = x;
shift_up(heap_size);
left--;
}
inline void extract()
{
heap[1] = heap[heap_size--];
shift_down(1);
}
int main()
{
int i, j;
freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &W, &H);
for (i = 0; i < H; i++)
for (j = 0; j < W; j++)
scanf("%d", &map[i][j]);
left = W * H;
for (i = 0; i < H; i++) {
insert(i, 0);
insert(i, W - 1);
}
for (i = 1; i < W - 1; i++) {
insert(0, i);
insert(H - 1, i);
}
while (left) {
i = heap[1].y;
j = heap[1].x;
extract();
insert(i - 1, j, fil[i][j]);
insert(i + 1, j, fil[i][j]);
insert(i, j - 1, fil[i][j]);
insert(i, j + 1, fil[i][j]);
}
printf("%d\n", ans);
return 0;
}
#define SIZE 332
struct heap_node {
int x, y;
} ;
int W, H;
int map[SIZE][SIZE], fil[SIZE][SIZE];
struct heap_node heap[SIZE * SIZE];
int heap_size, left, ans;
inline int cmp( struct heap_node * a, struct heap_node * b)
{
return fil[a->y][a->x] - fil[b->y][b->x];
}
inline void shift_down( int idx)
{
struct heap_node val = heap[idx];
while (1) {
idx *= 2;
if (idx > heap_size)
break;
if (idx + 1 <= heap_size && cmp(&heap[idx + 1], &heap[idx]) < 0)
idx++;
if (cmp(&val, &heap[idx]) <= 0)
break;
heap[idx / 2] = heap[idx];
}
heap[idx / 2] = val;
}
inline void shift_up( int idx)
{
struct heap_node val = heap[idx];
while (1) {
if (idx / 2 <= 0)
break;
if (cmp(&heap[idx / 2], &val) <= 0)
break;
heap[idx] = heap[idx / 2];
idx /= 2;
}
heap[idx] = val;
}
inline void insert( int y, int x, int f = - 1 )
{
if (y < 0 || y >= H || x < 0 || x >= W || fil[y][x])
return ;
if (map[y][x] > f)
f = map[y][x];
else
ans += f - map[y][x];
fil[y][x] = f;
heap_size++;
heap[heap_size].y = y;
heap[heap_size].x = x;
shift_up(heap_size);
left--;
}
inline void extract()
{
heap[1] = heap[heap_size--];
shift_down(1);
}
int main()
{
int i, j;
freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &W, &H);
for (i = 0; i < H; i++)
for (j = 0; j < W; j++)
scanf("%d", &map[i][j]);
left = W * H;
for (i = 0; i < H; i++) {
insert(i, 0);
insert(i, W - 1);
}
for (i = 1; i < W - 1; i++) {
insert(0, i);
insert(H - 1, i);
}
while (left) {
i = heap[1].y;
j = heap[1].x;
extract();
insert(i - 1, j, fil[i][j]);
insert(i + 1, j, fil[i][j]);
insert(i, j - 1, fil[i][j]);
insert(i, j + 1, fil[i][j]);
}
printf("%d\n", ans);
return 0;
}
Pascal:
Pascal:
{$m $100000} {由于我是做的DFS进行FLOODFILL,所以不免开了点栈深度}
Program Gp ;
const
maxn = 300 ;
dx : array[ 0 .. 3 ] of - 1 .. 1 = ( 0 , 1 , 0 , - 1 ) ;
dy : array[ 0 .. 3 ] of - 1 .. 1 = ( 1 , 0 , - 1 , 0 ) ;
zy = trunc( 1e9 ) ;
type
heaptype =
record
x , y , val : longint ;
end ;
var
map , f : array[ 0 .. maxn , 0 .. maxn ] of longint ;
use , u : array[ 0 .. maxn , 0 .. maxn ] of boolean ;
heap : array[ 0 .. maxn * maxn ] of heaptype ;
n , m , ans , len : longint ;
cant : boolean ;
procedure init ;
var
i , j : longint ;
begin
fillchar( f , sizeof ( f ) , 0 ) ;
readln( m , n ) ;
for i : = 1 to n do
for j : = 1 to m do
begin
read( map[ i , j ] ) ; f[ i , j ] : = zy ;
end ;
end ;
procedure ins( x , y , val : longint ) ;
var
t : heaptype ;
i : longint ;
begin
t.x : = x ; t.y : = y ; t.val : = val ;
inc( len ) ; i : = len ;
while ( i <> 1 ) and ( heap[ i div 2 ] . val > val ) do
begin
heap[ i ] : = heap[ i div 2 ] ;
i : = i div 2 ;
end ;
heap[ i ] : = t ;
end ;
procedure sort( ii : longint ) ;
var
j : longint ;
num : heaptype ;
begin
num : = heap[ ii ] ;
j : = ii * 2 ;
while j <= len do
begin
if ( j < len ) and ( heap[ j ] . val > heap[ j + 1 ] . val ) then inc( j ) ;
if num . val > heap[ j ] . val then
begin
heap[ ii ] : = heap[ j ] ;
ii : = j ;
j : = ii * 2 ;
end else break ;
end ;
heap[ ii ] : = num ;
end;
procedure dfs( x , y , max , deep : longint ) ;
var
i , xx , yy : longint ;
begin
u[ x , y ] : = false ;
if ( max < f[ x , y ] ) then f[ x , y ] : = max ;
for i : = 0 to 3 do
begin
xx : = x + dx[ i ] ; yy : = y + dy[ i ] ;
if ( xx <= 0 ) or ( xx > n ) or ( yy <= 0 ) or ( yy > m ) or ( not u[ xx , yy ] ) then continue ;
if map[ xx , yy ] <= max then dfs( xx , yy , max , deep + 1 )
else begin
if use[ xx , yy ] then
begin
ins( xx , yy , map[ xx , yy ] ) ;
use[ xx , yy ] : = false ;
end ;
end ;
end ;
end ;
procedure floodfill( x : heaptype ) ;
var
cici , i , a , b : longint ;
begin
if f[ x.x , x.y ] = zy then f[ x.x , x.y ] : = map[ x.x , x.y ] ;
dfs( x.x , x.y , f[ x.x , x.y ] , 1 ) ;
end ;
procedure solve ;
var
i , j : longint ;
now : heaptype ;
begin
fillchar( u , sizeof ( u ) , true ) ;
fillchar( use , sizeof ( use ) , true ) ;
len : = 0 ;
for i : = 1 to n do
begin
if use[ i , 1 ] then ins( i , 1 , map[ i , 1 ] ) ; use[ i , 1 ] : = false ; f[ i , 1 ] : = map[ i , 1 ] ;
if use[ i , m ] then ins( i , m , map[ i , m ] ) ; use[ i , m ] : = false ; f[ i , m ] : = map[ i , m ] ;
end ;
for i : = 1 to m do
begin
if use[ 1 , i ] then ins( 1 , i , map[ 1 , i ] ) ; use[ 1 , i ] : = false ; f[ 1 , i ] : = map[ 1 , i ] ;
if use[ n , i ] then ins( n , i , map[ n , i ] ) ; use[ n , i ] : = false ; f[ n , i ] : = map[ n , i ] ;
end ;
while len > 0 do
begin
now : = heap[ 1 ] ; heap[ 1 ] : = heap[ len ] ;
heap[ len ] . val : = maxlongint ; dec( len ) ;
sort( 1 ) ;
floodfill( now ) ;
end ;
end ;
procedure print ;
var
i , j , ans : longint ;
begin
ans : = 0 ;
for i : = 1 to n do
for j : = 1 to m do inc( ans , f[ i , j ] - map[ i , j ] ) ;
writeln( ans ) ;
end ;
procedure main ;
begin
init ;
solve ;
print ;
end ;
Begin
main ;
end .
{$m $100000} {由于我是做的DFS进行FLOODFILL,所以不免开了点栈深度}
Program Gp ;
const
maxn = 300 ;
dx : array[ 0 .. 3 ] of - 1 .. 1 = ( 0 , 1 , 0 , - 1 ) ;
dy : array[ 0 .. 3 ] of - 1 .. 1 = ( 1 , 0 , - 1 , 0 ) ;
zy = trunc( 1e9 ) ;
type
heaptype =
record
x , y , val : longint ;
end ;
var
map , f : array[ 0 .. maxn , 0 .. maxn ] of longint ;
use , u : array[ 0 .. maxn , 0 .. maxn ] of boolean ;
heap : array[ 0 .. maxn * maxn ] of heaptype ;
n , m , ans , len : longint ;
cant : boolean ;
procedure init ;
var
i , j : longint ;
begin
fillchar( f , sizeof ( f ) , 0 ) ;
readln( m , n ) ;
for i : = 1 to n do
for j : = 1 to m do
begin
read( map[ i , j ] ) ; f[ i , j ] : = zy ;
end ;
end ;
procedure ins( x , y , val : longint ) ;
var
t : heaptype ;
i : longint ;
begin
t.x : = x ; t.y : = y ; t.val : = val ;
inc( len ) ; i : = len ;
while ( i <> 1 ) and ( heap[ i div 2 ] . val > val ) do
begin
heap[ i ] : = heap[ i div 2 ] ;
i : = i div 2 ;
end ;
heap[ i ] : = t ;
end ;
procedure sort( ii : longint ) ;
var
j : longint ;
num : heaptype ;
begin
num : = heap[ ii ] ;
j : = ii * 2 ;
while j <= len do
begin
if ( j < len ) and ( heap[ j ] . val > heap[ j + 1 ] . val ) then inc( j ) ;
if num . val > heap[ j ] . val then
begin
heap[ ii ] : = heap[ j ] ;
ii : = j ;
j : = ii * 2 ;
end else break ;
end ;
heap[ ii ] : = num ;
end;
procedure dfs( x , y , max , deep : longint ) ;
var
i , xx , yy : longint ;
begin
u[ x , y ] : = false ;
if ( max < f[ x , y ] ) then f[ x , y ] : = max ;
for i : = 0 to 3 do
begin
xx : = x + dx[ i ] ; yy : = y + dy[ i ] ;
if ( xx <= 0 ) or ( xx > n ) or ( yy <= 0 ) or ( yy > m ) or ( not u[ xx , yy ] ) then continue ;
if map[ xx , yy ] <= max then dfs( xx , yy , max , deep + 1 )
else begin
if use[ xx , yy ] then
begin
ins( xx , yy , map[ xx , yy ] ) ;
use[ xx , yy ] : = false ;
end ;
end ;
end ;
end ;
procedure floodfill( x : heaptype ) ;
var
cici , i , a , b : longint ;
begin
if f[ x.x , x.y ] = zy then f[ x.x , x.y ] : = map[ x.x , x.y ] ;
dfs( x.x , x.y , f[ x.x , x.y ] , 1 ) ;
end ;
procedure solve ;
var
i , j : longint ;
now : heaptype ;
begin
fillchar( u , sizeof ( u ) , true ) ;
fillchar( use , sizeof ( use ) , true ) ;
len : = 0 ;
for i : = 1 to n do
begin
if use[ i , 1 ] then ins( i , 1 , map[ i , 1 ] ) ; use[ i , 1 ] : = false ; f[ i , 1 ] : = map[ i , 1 ] ;
if use[ i , m ] then ins( i , m , map[ i , m ] ) ; use[ i , m ] : = false ; f[ i , m ] : = map[ i , m ] ;
end ;
for i : = 1 to m do
begin
if use[ 1 , i ] then ins( 1 , i , map[ 1 , i ] ) ; use[ 1 , i ] : = false ; f[ 1 , i ] : = map[ 1 , i ] ;
if use[ n , i ] then ins( n , i , map[ n , i ] ) ; use[ n , i ] : = false ; f[ n , i ] : = map[ n , i ] ;
end ;
while len > 0 do
begin
now : = heap[ 1 ] ; heap[ 1 ] : = heap[ len ] ;
heap[ len ] . val : = maxlongint ; dec( len ) ;
sort( 1 ) ;
floodfill( now ) ;
end ;
end ;
procedure print ;
var
i , j , ans : longint ;
begin
ans : = 0 ;
for i : = 1 to n do
for j : = 1 to m do inc( ans , f[ i , j ] - map[ i , j ] ) ;
writeln( ans ) ;
end ;
procedure main ;
begin
init ;
solve ;
print ;
end ;
Begin
main ;
end .