floodfill算法 建立一个队列Q。初始时,Q仅包含最开始的那个“点”,对于每个出队的元素,把他周围需要扩散到的元素加到队列中。为了避免重复访问,需要记录每个元素是否已经访问过,即访问标志。他是一种很常用的预处理方法,当“连在一起很大一块东西可以一并处理”的时候,可以作一次floodfill,分离出一个个“连在一起”的块,然后再做处理。
对于本题,经验告诉我们,“一个桶最大的容量取决于它最短的那块板”。所以我们先对周围的一圈格子进行访问,并取其中最短具有最短长度的格子,将其加入队列中。然后进行floodfill,搜索到没有被访问过的并且高度更低的格子即将当前访问的格子与刚出队的元素的高度差加入到答案中,并将该格子加入到队列中。
floodfill
floodfill算法 建立一个队列Q。初始时,Q仅包含最开始的那个“点”,对于每个出队的元素,把他周围需要扩散到的元素加到队列中。为了避免重复访问,需要记录每个元素是否已经访问过,即访问标志。他是一种很常用的预处理方法,当“连在一起很大一块东西可以一并处理”的时候,可以作一次floodfill,分离出一个个“连在一起”的块,然后再做处理。 对于本题,经验告诉我们,“一个桶最大的容量取决于它最短的那块板”。所以我们先对周围的一圈格子进行访问,并取其中最短具有最短长度的格子,将其加入队列中。然后进行floodfill,搜索到没有被访问过的并且高度更低的格子即将当前访问的格子与刚出队的元素的高度差加入到答案中,并将该格子加入到队列中。 #include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; #define ll long long const int maxn = 333; int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} }; struct Pan{ int x,y; int h; friend bool operator < (Pan a, Pan b) { return a.h > b.h; } }pan; priority_queue <Pan> Q; int n,m; int G[maxn][maxn]; bool vis[maxn][maxn]; ll ans; void init() { memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(i == 0 || j == 0 || i == n-1 || j == m-1) { pan.x = i ;pan.y = j; pan.h = G[i][j]; Q.push(pan); vis[i][j] = 1; } } void floodfill() { Pan u, v; while(!Q.empty()) { u =Q.top(); Q.pop(); for(int i=0;i<4;i++) { int x = u.x +dir[i][0]; int y = u.y +dir[i][1]; if(x<0 || x>=n || y<0 || y>=m) continue; if(vis[x][y]) continue; vis[x][y] = 1; v.x = x; v.y = y; if(G[x][y] < u.h) { ans += u.h - G[x][y]; G[x][y] = u.h; v.h = G[x][y]; } else { v.h = G[x][y]; } Q.push(v); } } printf("%lld\n",ans); } int main() { while(~scanf("%d%d",&m,&n)) { for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&G[i][j]); init(); ans = 0; floodfill(); } return 0; }