Save Private Ryan (shortest path, state compression)

Insert picture description here

Idea: To find the shortest distance to point N, M, when there is a door, you need to use the corresponding key to open the door, then we use dis[i][j] to indicate that the state of the key held at the position of number i is j The shortest distance. According to the number id of the key, we initialize the state of the Key as Key=1<<id-1, we can find that when there is a key in this position, our state will change state=state(original)|key and then see if it needs to be updated Dis can get the transfer equation dis[i][state]=dis[i][state(original)|key], and then move up, down, left, and right. When moving, we need to judge whether there is a door. When there is a door, we need Determine whether there is a key for this position in the state where we hold the key at this position. If the position is W, we will see that 1>>w-1&1 is 0, which means there is no door key. The problem map is relatively pitted. First, we change the position of each point x, y into a number, and then enter the position of the wall and the door. If it is a wall, don’t care, if it is a door, create an edge and use the number of the door Weight, in order to judge whether there is a door in this position later, let's add all the numbers of the positions of the doors and walls entered into the set. Later, we will add edges to the entire picture. If this number is not used at this time, it means that they are between There are sides, each number usually has 4 sides, so use the dir array.

Code:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
#define SIS std::ios::sync_with_stdio(false)
#define space putchar(' ')
#define enter putchar('\n')
#define lson root<<1
#define rson root<<1|1
typedef pair<int,int> PII;
typedef pair<int,PII> PIII;
const int mod=1e9+7;
const int N=2e5+5;
const int inf=0x7f7f7f7f;

int gcd(int a,int b)
{
    
    
    return b==0?a:gcd(b,a%b);
}
 
ll lcm(ll a,ll b)
{
    
    
    return a*(b/gcd(a,b));
}
 
template <class T>
void read(T &x)
{
    
    
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-')
            op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op)
        x = -x;
}
template <class T>
void write(T x)
{
    
    
    if(x < 0)
        x = -x, putchar('-');
    if(x >= 10)
         write(x / 10);
    putchar('0' + x % 10);
}
ll qsm(int a,int b,int p)
{
    
    
    ll res=1%p;
    while(b)
    {
    
    
        if(b&1)
            res=res*a%p;
        a=1ll*a*a%p;
        b>>=1;
    }
    return res;
}
struct node
{
    
    
    int to,nex,w;
}edge[400];
const int P=1<<10;
int head[400],dis[400][P],vis[400][P];
int g[400][400],key[400];
int tot;
int n,m,s,k;
set<PII> edges;
void add(int u,int v,int w)
{
    
    
    edge[tot].w=w;
    edge[tot].to=v;
    edge[tot].nex=head[u];
    head[u]=tot++;
}
int dir[4][2]={
    
    {
    
    1,0},{
    
    -1,0},{
    
    0,1},{
    
    0,-1}};

void build()
{
    
    
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      for(int u=0;u<4;u++)
      {
    
    
          int x=i+dir[u][0],y=j+dir[u][1];
          if(!x||x>n||!y||y>m)continue;
          int a=g[i][j],b=g[x][y];
          if(edges.count({
    
    a,b})==0){
    
    
              add(a,b,0);
              add(b,a,0);
          }
      }
   
}

int bfs()
{
    
    
    memset(dis,inf,sizeof dis);
    memset(vis,0,sizeof vis);
    dis[1][0]=0;
    deque<PII> q;
    q.push_back({
    
    1,0});
    while(q.size())
    {
    
    
        
        PII now=q.front();q.pop_front();
        int u=now.first,sta=now.second;
        //cout<<u<<endl;
        if(vis[u][sta])continue;
        vis[u][sta]=1;
        if(u==n*m) return dis[u][sta];
        
        if(key[u])
        {
    
    
            int state=sta|key[u];
            if(dis[u][state]>dis[u][sta])
            {
    
    
                dis[u][state]=dis[u][sta];
                q.push_front({
    
    u,state});
            }
        }
       // cout<<"2--"<<u<<endl;
        for(int i=head[u];~i;i=edge[i].nex)
        {
    
    
            int v=edge[i].to,w=edge[i].w;
            if(w && !(sta >> w - 1 & 1) ) continue;
            if(dis[v][sta]>dis[u][sta]+1)
            {
    
    
                dis[v][sta]=dis[u][sta]+1;
                q.push_back({
    
    v,sta});
            }
        }

    }
    return -1;

}




int main()
{
    
    
   cin>>n>>m>>s>>k;
   memset(head,-1,sizeof head);
   
   for(int i=1,t=1;i<=n;i++)
       for(int j=1;j<=m;j++)
           g[i][j]=t++;

   while(k--)
   {
    
    
       int x1,x2,y1,y2,op;
       cin>>x1>>y1>>x2>>y2>>op;
       int a=g[x1][y1],b=g[x2][y2];
       edges.insert({
    
    a,b});edges.insert({
    
    b,a});
       if(op){
    
    
           add(a,b,op);add(b,a,op);
       }

   }
    build();

   int rz;
   cin>>rz;
   while(rz--)
   {
    
    
       int x,y,c;
       cin>>x>>y>>c;
       key[g[x][y]]|=1<<c-1;
      

   }
  
   cout<<bfs()<<endl;


   return 0;

}


Guess you like

Origin blog.csdn.net/qq_43619680/article/details/112983015