这是一个典型的多源BFS问题
,如果初学数据结构的同学,可能第一次不能想到,但是如果做过一次应该就能运用了。
主要思路大概是初始时,多个点进入队列然后进行BFS。将某一等价集合视作同一个起始点(超级源点
),先将此源点入队,再一层一层向外扩张。相当于这些初始出队的源点在整个问题中地位等价。另外还可以视作不同的起点同时进行BFS操作,而不需要依次作为起点依次BFS,有时写在一起更方便。
腐烂的橘子:
由于这里腐烂的橘子应该是同时向外感染腐烂的,如果分不同次进行BFS问题会很棘手,但是如果将腐烂的橘子进行多源BFS,则最后一层实际上就是最后腐烂的橘子,它腐烂的时间就是整个问题的答案。
这里使用tuple存储顶点信息,很方便。
class Solution {
public:int orangesRotting(vector<vector<int>>& grid) {queue<tuple<int,int,int> > q;int num=0;//记录剩余新鲜橘子个数m=grid.size(),n=grid[0].size();for(int i=0;i<m;++i)for(int j=0;j<n;++j)if(grid[i][j]==2){q.push({i,j,0});//存放腐坏橘子位置以及它腐坏时经过的时间}else if(grid[i][j]) num++;int ans=-1;while(!q.empty()&&num){int x=get<0>(q.front());int y=get<1>(q.front());ans=get<2>(q.front()); q.pop();//时间一定为不减序列for(int k=0;k<4;++k){int i=dx[k],j=dy[k];if(check(x+i,y+j)&&grid[x+i][y+j]==1){grid[x+i][y+j]=2;q.push(make_tuple(x+i,y+j,ans+1));--num;}}}if(num!=0) return -1;return ans+1;//ans+1是答案的原因是:当num==0时,已经没有腐坏橘子可以更新了,会直接break,但是此时最外层福坏橘子的ans并未被记录成答案}
private:bool check(int x,int y){if(x>=0&&x<m&&y>=0&&y<n) return true;return false;}int m,n;const int dx[4]={0,1,0,-1};const int dy[4]={-1,0,1,0};
};
许久没做图论问题,把方向写错了,感觉是惯性思维了,这里记录下来防止以后又写错。写成了这样:
const int dx[4]={0,1,0,-1};
const int dy[4]={-1,0,1,0};
for(int i:dx)//wrong//wrong//wrong//wrong//wrong//wrong//wrongfor(int j:dy){//wrong//wrong//wrong//wrong//wrong//wrong//wrong//巴拉巴拉//wrong}//wrong
上述写法方向一共有4*4=16种,其中8个是正常的顶点四周的8个方向(左上,左,左下,上,下,右上,右,右下,对于每一个x方向遍历y),8个是无用的重复方向。而实际上方向只有四个,dx[i]和dy[i]组合形成一个方向,以下是正确方式
:
const int dx[4]={0,1,0,-1};
const int dy[4]={-1,0,1,0};
for(int k=0;k<4;++k){//正确打开方式,遍历四个方向i=x+dx[k];j=y+dy[k];g[i][j]=0;
}