Save Private Ryan (P4011 Island Rescue problem) (bfs + state compression)

Posted by purtip3154 on Mon, 07 Feb 2022 10:21:40 +0100

Title Description

In 1944, special forces Mike received an order from the Ministry of defense to rush to an isolated island in the Pacific Ocean to rescue Private Ryan captured by the enemy. Ryan was imprisoned in a maze with complex terrain, but fortunately Mike got the topographic map of the maze. The shape of the maze is a rectangle. Its north-south direction is divided into N rows and the east-west direction is divided into MM columns, so the whole maze is divided into N rows × M units. The position of each cell can be represented by an ordinal number pair (cell row number, cell column number). The two adjacent units in the North-South or east-west direction may be interconnected, there may be a locked door, or an insurmountable wall. Some units in the maze store keys, and all doors are divided into P categories. The keys to open the same category of doors are the same, and the keys of different categories of doors are different.

Private Ryan was held in the southeast corner of the maze, unit (N,M), and was unconscious. The maze has only one entrance, in the northwest corner. That is, the microphone can directly enter the (1,1) unit. In addition, the time for the microphone to move from one unit to another adjacent unit is 1, and the time for taking the key of the unit and opening the door with the key can be ignored.

Rescue Mike Ryan, try the fastest way to reach Ryan.

Input format

The first line has three integers representing the values of N, m and P.
The second line is an integer k, which represents the total number of doors and walls in the maze.
In line i+2 (1 ≤ i ≤ k), there are five integers, which are Xi1, Yi1, XI2, yi2 and gi in sequence: when gi ≥ 1, there is a door of class gi between (xi1,yi1) and (xi2,yi2) units; when gi=0, there is an insurmountable wall between (xi1,yi1) and (xi2,yi2) units.
Line k+3 is an integer s, which represents the total number of keys stored in the maze.
In line k+3+j (1 ≤ J ≤ s), there are three integers, which are Xi1, Yi1 and qi in sequence, indicating that the j-th key is stored in the (xi1,yi1) unit, and the j-th key is used to open the qi door.
Adjacent integers in the same row of input data are separated by a space.
|xi1−xi2|+|yi1−yi2|=1,0≤gi≤p|xi1−xi2|+|yi1−yi2|=1,0≤    gi≤p
1≤qi≤p
n,m,p≤10,k<150

Solution:

When searching for this topic before, I couldn't write it. After reading it, it seemed that I wanted to use network flow. The analysis on Xinao Yitong didn't understand it. Then I went to Luogu today and looked at the problem solution. I found that it was not as complex as I thought. It was mainly about the judgment of weight and the problem of whether I could go. If the judgment was heavy, I opened a vector < int > vis [16] [16] to mark it. As for the key, we need to use the knowledge of state compression. Each key can be regarded as a binary number. In detail, I recommend this knowledge introduction on Luogu. I also read this.

https://86971.blog.luogu.org/solution-p4011

I feel that he / she writes very well
Then there is the typical bfs. Walk in four directions. First judge whether the position is legal. If it is legal, then judge whether there is a wall or a door from the current position to another position
If there is a wall, there is no way. If there is a door and you can't get through without a key, you can go through other situations.
I use mp[16][16][16][16], a four-dimensional array to save the map representation (x1, Y1) - > (X2, Y2). It has just been initialized to - 1, indicating that it can go through, and then change it according to the input. For example, the wall is 0.
(1 < < MP [X1] [Y1] [x2] [Y2]) and the current key. If the result is zero, it means that he can't open the door without this key. Otherwise.
Attention
• There may be multiple keys in one position, which can be reused, and there may also be keys in the initial position
• Pay attention to the data range
```#include<bits/stdc++.h>
using namespace std;
int N,M,P,K,S;
int mp[16][16][16][16];
vector<int> key[16][16];//How many keys can there be in one place
int dir[4][2]={-1,0,0,1,1,0,0,-1};
vector<int> vis[16][16];//Use this array to save the state
struct node{
int x,y;//Current coordinates and number of keys / / binary indicates the key
int step,k;
}start;
inline bool Catch(node &a)
{
if(a.x==N&&a.y==M) return true;
return false;
}
bool check(int x,int y,node a)
{
if(x<1||x>N||y<1||y>M) return false;
int t=mp[a.x][a.y][x][y];
if(t==-1) return true;
else if(t==0) return false;
else{
if(((1<<t)&a.k)>0) return true;  //Put parentheses, or you'll make an error
else return false;
}
}
int bfs()
{
start.x=1,start.y=1,start.step=0;
for(int i=0;i<key[1][1].size();++i)
start.k|=1<<key[1][1][i];
vis[1][1].push_back(start.k);
queue<node>Q;
Q.push(start);
while(!Q.empty())
{
start=Q.front();Q.pop();
if(Catch(start)) return start.step;
for(int i=0;i<4;++i)
{
node r=start;
int x=r.x+dir[i][0],y=r.y+dir[i][1];
r.x=x,r.y=y,r.step++;
for(int j=0;j<key[x][y].size();++j)
r.k|=(1<<key[x][y][j]); //Put parentheses, or you'll make a mistake
int tag=0;
for(int j=0;j<vis[r.x][r.y].size();++j)
if(tag)continue;
if(Catch(r)) return r.step;
vis[r.x][r.y].push_back(r.k);
Q.push(r);
}
}
return -1;
}
int main()
{
//int N,M,P,K,S;
memset(mp,-1,sizeof(mp)); //-1 indicates that the surroundings are connected and can walk
cin>>N>>M>>P;
cin>>K;
int x1,y1,x2,y2,g,q;
for(int i=1;i<=K;++i)
{
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g);
mp[x1][y1][x2][y2]=g;  //Bidirectional channel
mp[x2][y2][x1][y1]=g;
}
cin>>S;
for(int j=1;j<=S;++j)
{
scanf("%d%d%d",&x1,&y1,&q);
key[x1][y1].push_back(q);
}
cout<<bfs();
return(0);
}

```