目录
显示
题目链接
https://www.luogu.org/problem/P3489
题解
\(p\) 的范围很小,考虑状态压缩+分层图最短路。
我们设 \(dist_{i,sta}\) 表示从 \(1\) 号点到 \(i\) 号点,能打败的怪物为 \(sta\) 时的最短路。
转移的时候额外判断一下一条边能否通过(用位运算)即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
struct edge
{
int v,w,p,next;
}e[6005];
struct node
{
int u,p;
};
int head[205],dist[205][40005],vis[205][40005],a[205],n,m,p,k,cnt;
queue<node> q;
void addedge(int u,int v,int w,int p)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].p=p;
e[cnt].next=head[u];
head[u]=cnt;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&p,&k);
for(int i=1;i<=k;i++)
{
int w,q;
scanf("%d%d",&w,&q);
for(int j=1;j<=q;j++)
{
int x;
scanf("%d",&x);
a[w]|=(1<<x);
}
}
for(int i=1;i<=m;i++)
{
int u,v,t,s,tmp=0;
scanf("%d%d%d%d",&u,&v,&t,&s);
for(int j=1;j<=s;j++)
{
int x;
scanf("%d",&x);
tmp|=(1<<x);
}
addedge(u,v,t,tmp);
addedge(v,u,t,tmp);
}
memset(dist,INF,sizeof(dist));
dist[1][a[1]]=0,vis[1][a[1]]=1;
q.push({1,a[1]});
while(!q.empty())
{
int u=q.front().u,p=q.front().p;
q.pop();
vis[u][p]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v,w=e[i].w,np=e[i].p;
if((np&p)==np&&dist[v][p|a[e[i].v]]>dist[u][p]+w)
{
dist[v][p|a[e[i].v]]=dist[u][p]+w;
if(!vis[v][p|a[e[i].v]])
{
vis[v][p|a[e[i].v]]=1;
q.push({v,p|a[e[i].v]});
}
}
}
}
int ans=INF;
for(int i=0;i<=(1<<(p+1));i++)
ans=min(ans,dist[n][i]);
printf("%d\n",ans==INF?-1:ans);
return 0;
}