P3489 [POI2009]WIE-Hexer
P3489:https://www.luogu.com.cn/problem/P3489
bzoj1139:https://darkbzoj.tk/problem/1139
dij 分层图最短路+状态压缩,把状态大小上限 \(2^p-1\) 写成了 \(2^{p-1}-1\),然后debug了将近一晚上。。。
由于 \(p\le 13\),而且当前能走哪些路不能走哪些,又和每一个剑的有无有关,所以我们用一个 13 为二进制数来表示当前状态下,每一个剑有没有
\(dis_{i,S}\) 表示的就是从 \(1\) 到 \(i\),且状态为 \(S\) 所需的最短路程
答案就是 \(\min\{dis_{n,S},S< 2^p\}\)
这里为了 dij 那里处理起来方便 复制板子方便,直接将这两维用一个数表示了,具体看 id
数组
然后 dij 中的每当开始处理一个 \(u\),就用当前节点铁匠的信息,来更新 \(S\),枚举出边的时候在判断一下当前这条边能不能走就行了
应该还是挺简单
话说这题是当时刚学 dij 的时候,连堆优化都还不会,就用 dij 的标签搜进了这题,然后还码了半天,发现思路不对就直接让它进任务计划吃灰了
然后这一年多以后才想起来回来做
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
register int x=0;register int y=1;
register char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
#define N 1700005
#define M 6005
struct graph{
int fir[N],nex[M],to[M],w[M],tot;
inline void add(int u,int v,int z){
to[++tot]=v;w[tot]=z;
nex[tot]=fir[u];fir[u]=tot;
}
}G;
int n,m,p,k;
int heap[N],size;
int dis[N],in[N];
int blacksmith[N],monster[M];
int id[205][9005];
int get_i[N],get_S[N];
inline void push(int x){
heap[++size]=x;
reg int i=size,fa;
while(i>1){
fa=i>>1;
if(dis[heap[fa]]<=dis[heap[i]]) return;
std::swap(heap[fa],heap[i]);i=fa;
}
}
inline int pop(){
int ret=heap[1];heap[1]=heap[size--];
reg int i=1,ls,rs;
while((i<<1)<=size){
ls=i<<1;rs=ls|1;
if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
if(dis[heap[i]]<=dis[heap[ls]]) break;
std::swap(heap[ls],heap[i]);i=ls;
}
return ret;
}
inline void dij(){
std::memset(dis,0x3f,sizeof dis);dis[id[1][blacksmith[1]]]=0;
push(id[1][blacksmith[1]]);in[id[1][blacksmith[1]]]=1;
reg int u,v,S;
while(size){
u=pop();in[u]=0;
S=get_S[u];
S|=blacksmith[get_i[u]];//能打造新的剑就一定造
for(reg int i=G.fir[get_i[u]];i;i=G.nex[i]){
if((S&monster[i])!=monster[i]) continue;
v=id[G.to[i]][S];
// printf("(%d %d)=> (%d %d)\n",u,v,get_i[u],get_i[v]);
if(dis[v]>dis[u]+G.w[i]){
dis[v]=dis[u]+G.w[i];
if(!in[v]) push(v),in[v]=1;
}
}
}
}
int main(){
n=read();m=read();p=read();k=read();
for(reg int w,num,i=1;i<=k;i++){
w=read();num=read();
while(num--) blacksmith[w]|=(1<<(read()-1));
}
for(reg int i=1,u,v,w,num;i<=m;i++){
u=read();v=read();w=read();num=read();
G.add(u,v,w);G.add(v,u,w);
while(num--){
u=read();
monster[G.tot]|=(1<<(u-1));
monster[G.tot-1]|=(1<<(u-1));
}
}
int id_=0;
for(reg int i=1;i<=n;i++)
for(reg int S=0;S<(1<<p);S++)
id[i][S]=++id_,get_i[id_]=i,get_S[id_]=S;
dij();
int ans=1e9;
for(reg int S=0;S<(1<<p);S++) ans=std::min(ans,dis[id[n][S]]);
printf("%d",ans==1e9?-1:ans);
return 0;
}