设状态$(x,y,h)$为 到点$(x,y)$当前钥匙集合为$h$的最短用时, $bfs$求出最短路即可.
#include <iostream> #include <algorithm> #include <cstdio> #include <set> #include <map> #include <queue> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) using namespace std; typedef tuple<int,int,int,int> t4; typedef tuple<int,int,int> t3; const int dx[]={0,0,-1,1}; const int dy[]={-1,1,0,0}; int n, m, p, k, s; map<t4,int> f; set<t3> vis; map<t3,int> dis; int a[20][20]; queue<t3> q; int main() { scanf("%d%d%d%d", &n, &m, &p, &k); REP(i,1,k) { int x1,y1,x2,y2,g; scanf("%d%d%d%d%d", &x1,&y1,&x2,&y2,&g); f[t4(x2,y2,x1,y1)] = f[t4(x1,y1,x2,y2)] = g?1<<g-1:1<<p; } scanf("%d", &s); REP(i,1,s) { int x,y,q; scanf("%d%d%d",&x,&y,&q); a[x][y] |= 1<<q-1; } q.push(t3(1,1,a[1][1])); dis[q.front()] = 0; vis.insert(q.front()); int ans = 1e9; while (q.size()) { t3 u = q.front(); q.pop(); int x,y,h; tie(x,y,h) = u; if (x==n&&y==m) ans = min(ans, dis[u]); REP(i,0,3) { int xx=x+dx[i],yy=y+dy[i]; if (1<=xx&&xx<=n&&1<=yy&&yy<=m) { t3 v(xx,yy,h|a[xx][yy]); if (vis.count(v)) continue; int t = f[t4(x,y,xx,yy)]; if ((h|t)==h) { dis[v] = dis[u]+1; vis.insert(v); q.push(v); } } } } printf("%d\n",ans==1e9?-1:ans); }
原文:https://www.cnblogs.com/uid001/p/10991677.html