题意:
就是给你一个n*m的网格,初始点为S,有的地方为障碍,初始点有两个人,现在问你,两个人把这个地图遍历一遍的最小时间。n,m<=5。
思考:
一看这个范围就是状态压缩,但是刚开始我不知道在想啥,还在想第一个人要走哪些点,然后他走的全排列方式,这肯定超时啊,你不要考虑那么多,既然是这种图上的问题,一般都是bfs的做法。所以先把所有点到达的状态记录下来,然后从初始点开始bfs,vis有5维,分别是当前对地图的覆盖状态,第一个人所在点,第二个人的所在点。然后就去跑bfs就行了,两重循环看看分别该怎么走,然后看看这种状态下的vis是否出现过,然后再判断一下就行了。
怎么说的,也不算新颖的题,其实只是以前做的比较少,只要在图上就要去想想bfs那种状态方式。
代码:
struct node{
int sta;
int x1,y1,x2,y2;
int dis;
};
int T,n,m,k;
int ans;
int minn = inf;
char va[M][M];
int vis[1ll<<17][5][5][5][5];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int get(int a,int b)
{
return (a-1)*m+b;
}
void bfs(int A,int B)
{
queue<node > q;
q.push({1ll<<get(A,B),A,B,A,B,0});
vis[1ll<<get(A,B)][A][B][A][B] = 1;
while(q.size())
{
auto now = q.front();
q.pop();
int sta = now.sta,dis = now.dis;
int x1 = now.x1,y1 = now.y1,x2 = now.x2,y2 = now.y2;
if(sta==ans)
{
minn = dis;
return ;
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int xx1 = x1+dx[i],yy1 = y1+dy[i];
int xx2 = x2+dx[j],yy2 = y2+dy[j];
if(xx1<1||xx1>n||yy1<1||yy1>m||xx2<1||xx2>n||yy2<1||yy2>m) continue;
if(va[xx1][yy1]=='X'||va[xx2][yy2]=='X') continue;
int state = sta|(1ll<<get(xx1,yy1))|(1ll<<get(xx2,yy2));
if(vis[state][xx1][yy1][xx2][yy2]) continue;
vis[sta][xx1][yy1][xx2][yy2] = 1;
q.push({state,xx1,yy1,xx2,yy2,dis+1});
}
}
}
}
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>va[i][j];
if(va[i][j]!='X') ans |= (1ll<<get(i,j));
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(va[i][j]=='S')
bfs(i,j);
}
}
cout<<minn<<"\n";
return 0;
}
总结:
多多积累经验呀。