牢骚写在前面
好久好久没有更过博客了
上一篇板子纯粹是为了自己记住,都没有好好写过题解了
自从考完noip,整个人都颓了,连“退役记”“游记”都没有写
不过,这些都不重要了
我还在这条路上摸爬滚打着
博客还是要更的
就像是日子总要过下去
Analysis
建图好题!
听说状压也可以乱搞,不过我还是乖乖练习一下建图
思考在一张图上,按照常规思路建图,然后跑最短路
如果没有钥匙,显然是可以的,问题是现在我们有钥匙,可以节省一些时间
问题就变成我们该选择拿哪一些钥匙,可以花费最少的时间到达终点
考虑如果拿到一把钥匙,其对应的门就可以直接走过去了
这就好比,拿到一把钥匙就进入了一个新世界,在这个世界里,原来有的路依然在,但由于有钥匙了,还有一些新的路可以被使用
抽象地理解这个了之后,我们就可以引入分层图了
在第0层里是没有任何一把钥匙的
下一层有一把钥匙
这样依次往下
建图细节看代码
最后跑一遍最短路即可
Code
#include<bits/stdc++.h>
#define in read()
#define int long long
#define re register
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9') {
res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return f==1?res:-res;
}
const int N=300009;
const int Mx=5000009;
int inf;
bool vis[N];
int n,m,k,d[N],s,g[200][200],keyn,M;
vector<pair<int,int> > V[200];
int nxt[Mx],to[Mx],head[N],w[Mx],ecnt=0;
inline void add(int x,int y,int z){ nxt[++ecnt]=head[x];head[x]=ecnt;to[ecnt]=y;w[ecnt]=z;}
inline int num(int x,int y){ return (x-1)*m+y;}
int layer;
inline void build(){
for(re int p=0;p<=layer;++p){
for(re int q=1;q<=keyn;++q)
vis[q]=p&(1<<q-1);
for(re int i=1;i<=n;++i)
for(re int j=1;j<=m;++j){
int x=num(i,j),y=num(i,j+1);
if(j<m&&g[x][y]!=-1) {
if(g[x][y]==0||vis[g[x][y]])
add(M*p+x,M*p+y,1),add(M*p+y,M*p+x,1);
}
y=num(i+1,j);
if(i<n&&g[x][y]!=-1){
if(g[x][y]==0||vis[g[x][y]])
add(M*p+x,M*p+y,1),add(M*p+y,M*p+x,1);
}
}
for(re int q=1;q<=keyn;++q){
if(!vis[q]){
int tmp=p+(1<<q-1);
for(re int i=0;i<V[q].size();++i){
int x=num(V[q][i].first,V[q][i].second);
add(M*p+x,M*tmp+x,0);
}
}
}
}
}
inline void dij(){
priority_queue<pair<int,int> > q;
memset(d,127/3,sizeof(d));
inf=d[1];
d[1]=0;q.push(make_pair(0,1));
memset(vis,0,sizeof(vis));
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u]) continue;
vis[u]=1;
for(re int e=head[u];e;e=nxt[e]){
int v=to[e];
if(d[v]>d[u]+w[e]){
d[v]=d[u]+w[e];
q.push(make_pair(-d[v],v));
}
}
}
}
signed main(){
n=in;m=in;keyn=in;k=in;int xx,yy,xxx,yyy,ch;
M=n*m;layer=(1<<keyn)-1;
for(re int i=1;i<=k;++i){
xx=in;yy=in;xxx=in;yyy=in;ch=in;
int x=num(xx,yy),y=num(xxx,yyy);
if(ch>=1) g[x][y]=ch;//door
if(ch==0) g[x][y]=-1;//wall
//默认情况=0 则表示无门无墙
}
s=in;
for(re int i=1;i<=s;++i){
xx=in;yy=in;ch=in;
V[ch].push_back(make_pair(xx,yy));
}
build();
dij();
int ans=inf;
for(re int i=0;i<=layer;++i) ans=min(ans,d[i*M+M]);
if(ans==inf) cout<<-1;
else cout<<ans;
return 0;
}