题意:A和B两个人从1个点出发,问走遍整张图最少要多少时间
思路:
用dis[x1][y1][x2][y2][statu]:A在(x1,y1),B在(x2,y2)遍历过点用statu的二进制状态表示
接下来暴力bfs
用二进制来表示转移过的点。还有vis数组标记一定要写在入队的地方,写在出队的地方复杂度翻一番
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
using namespace std;
typedef long long ll;
template <class T>
bool sf(T &ret){ //Faster Input
char c; int sgn; T bit=0.1;
if(c=getchar(),c==EOF) return 0;
while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
if(c==' '||c=='\n'){ ret*=sgn; return 1; }
while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
ret*=sgn;
return 1;
}
int all,sx,sy,n,m;
char mp[5][5];
int HASH(int i , int j){
return 1<<((i-1)*m+j);
}
struct node{
int x1,y1,x2,y2,s;
};
int dir[4][2]={1,0,-1,0,0,1,0,-1};
bool vis[5][5][5][5][1<<17];
int dis[5][5][5][5][1<<17];
bool check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m) return true;
return false;
}
ll cnt;
int bfs(){
queue <node> q;
q.push((node){sx,sy,sx,sy,HASH(sx,sy)});
while(!q.empty()){
node now=q.front();
q.pop();
if(now.s==all){
return dis[now.x1][now.y1][now.x2][now.y2][now.s];
}
// vis如果写在这里,很多点会反复入队。
// vis[now.x1][now.y1][now.x2][now.y2][now.s]=true;
for(int i=0;i<=3;i++){
int nx1=now.x1+dir[i][0],ny1=now.y1+dir[i][1];
if(!check(nx1,ny1) || mp[nx1][ny1]=='X') continue;
for(int j=0;j<=3;j++){
int nx2=now.x2+dir[j][0],ny2=now.y2+dir[j][1];
int gg=now.s|(HASH(nx1,ny1))|(HASH(nx2,ny2));
if(!check(nx2,ny2) || vis[nx1][ny1][nx2][ny2][gg] || mp[nx2][ny2]=='X') continue;
node t=(node){nx1,ny1,nx2,ny2,gg};
vis[nx1][ny1][nx2][ny2][gg]=true;
dis[nx1][ny1][nx2][ny2][gg]=dis[now.x1][now.y1][now.x2][now.y2][now.s]+1;
q.push(t);
}
}
}
return 0;
}
int main(void){
sf(n);sf(m);
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='X') continue;
else if(mp[i][j]=='S') sx=i,sy=j;
all = all|HASH(i,j);
}
}
printf("%d\n",bfs());
return 0 ;
}