【JZOJ 5459】密室【最短路】
阿新 • • 發佈:2018-12-10
題目大意:
思路:
終於找到一道的變形的題目了。。。
這道題在普通的基礎上增加了條件,如果能處理好這些條件,那麼就是一個裸的。
我們可以用狀態壓縮儲存每個點有的鑰匙和每條路需要的鑰匙,每條路需要的鑰匙可以直接在結構體裡面加上一維。
然後再跑的時候,再加上一個佇列,的每一位應該和的每一位兩兩對應。儲存的是到達這個狀態的時候的鑰匙壓縮後的數字。
那麼當我們決定要走這條路的時候,除了本身的距離判斷,還要再加上一個現在擁有的鑰匙是否可以走這條路
最後列舉到達終點時的鑰匙,並輸出最小值即可。
程式碼:
#include <cstdio>
#include <queue>
#include <cstring>
#include <map>
#define N 6100
#define Inf 1e9
using namespace std;
int n,m,k,tot,key[N],head[N],dis[N][1024 ],x,y,z;
bool vis[N][1024];
struct edge
{
int next,to,key;
}e[N];
void add(int from,int to,int num)
{
tot++;
e[tot].to=to;
e[tot].key=num;
e[tot].next=head[from];
head[from]=tot;
}
void spfa()
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f3f3f3f,sizeof(dis));
vis[1][key[1 ]]=1;
dis[1][key[1]]=0; //第二維表示到達這個點時鑰匙壓縮後的數字
queue<int> q;
queue<int> keynum;
q.push(1);
keynum.push(key[1]);
while (q.size())
{
int num=keynum.front();
keynum.pop();
int u=q.front();
q.pop();
vis[u][num]=0;
for (int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if (((num&e[i].key)==e[i].key)&&(dis[v][num|key[v]]>dis[u][num]+1)) //num|key[v]是到達v點之後的鑰匙數量
{
dis[v][num|key[v]]=dis[u][num]+1;
if (!vis[v][num|key[v]])
{
vis[v][num|key[v]]=1;
q.push(v);
keynum.push(num|key[v]);
}
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++)
for (int j=k;j>=1;j--)
{
scanf("%d",&x);
if (x) key[i]+=(1<<(j-1));
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
int num=0;
for (int j=k;j>=1;j--)
{
scanf("%d",&z);
if (z) num+=(1<<(j-1));
}
add(x,y,num);
}
spfa();
int ans=Inf;
for (int i=0;i<=1023;i++)
ans=min(ans,dis[n][i]);
if (ans<Inf) printf("%d\n",ans);
else printf("No Solution");
return 0;
}