说一下简单思路
因为钥匙数目很少,可以直接用二进制保存所得的钥匙状态,所以,用6把钥匙+现在所在地点+已走的路径的长度来表示不同的状态,用队列queue实现广搜算法即可
ps:我之前用新建一个类来保存6把钥匙+当前所在地点,表示已经走过的状态,发现在重载<运算符(即cmp函数)的时候会报一些异常奇怪的错误,最后用pair来保存状态才过的,借此提示各位读者,set<class_name>要慎用,当然明白stl底层的大佬就随便用啦,,,好了,继续恶补stl源码
int desll[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct poi{
set<int> se;
int head , len;
poi(){}
poi(set<int> sefunc, int x , int le):se(sefunc),head(x),len(le){}
};
class Solution {
public:
int shortestPathAllKeys(vector<string>& grid) {
int n = grid.size() , m = grid[0].size();
int ins=0;
set<pair<int,int> > seAll;
int x=0,y=0;
for(int i=0; i<n; i++){
for(int j=0;j<m;j++){
if(grid[i][j] <= 'z' && grid[i][j] >= 'a')ins++;
if(grid[i][j] == '@'){
x = i;
y = j;
}
}
}
seAll.clear();
queue<poi> qu;
int NewHead=x*m+y;
set<int> setShort;
qu.push(poi(setShort, NewHead,0));
seAll.insert(make_pair(0,NewHead));
while(qu.size()){
set<int> seMid = qu.front().se;
int headMid = qu.front().head;
int lenMid = qu.front().len;
int u = headMid / m , v = headMid % m;
if((int)seMid.size()==ins)return lenMid;
lenMid++;
qu.pop();
for(int i=0; i<4; i++){
int newx = u + desll[i][0] , newy = v + desll[i][1];
if(newx >=0 && newx < n && newy >= 0 && newy < m && grid[newx][newy]!='#'){
set<int> seMidm = seMid;
if(grid[newx][newy]<='Z'&&grid[newx][newy]>='A'){
if(seMid.count(grid[newx][newy]-'A')==0)continue;
}
if(grid[newx][newy] <= 'z' && grid[newx][newy] >= 'a')
seMidm.insert(grid[newx][newy]-'a');
int newHead = newx * m + newy;
int arr[6]={0,0,0,0,0,0};
int paFir=0;
for(auto au=seMidm.begin();au!=seMidm.end();au++)paFir ^= (1<<(*au));
if(seAll.count(make_pair(paFir , newHead))==0){
seAll.insert(make_pair(paFir , newHead));
qu.push(poi(seMidm , newHead , lenMid));
}
}
}
}
return -1;
}
};