【JZOJ 5459】密室【最短路】

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/82713795

题目大意:

题目链接:https://jzoj.net/senior/#main/show/5459
题目图片:
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fva78gse8vj30jc0fu3z6.jpg
http://wx2.sinaimg.cn/mw690/0060lm7Tly1fva78grjjuj30jb072t8m.jpg
http://wx1.sinaimg.cn/mw690/0060lm7Tly1fva78gsbd8j30hk0c1aa8.jpg
给出一个有向图,走一条边需要一些钥匙,只有拥有这些钥匙才可以走,走完后钥匙不会消失。到达点可以获得在这个点上的钥匙。求从 1 n 的最短路。(边权均为1)


思路:

终于找到一道 S P F A 的变形的题目了。。。
这道题在普通 S P F A 的基础上增加了条件,如果能处理好这些条件,那么就是一个裸的 S P F A
我们可以用状态压缩储存每个点有的钥匙和每条路需要的钥匙,每条路需要的钥匙可以直接在结构体里面加上一维 e [ i ] . k e y
然后再跑 S P F A 的时候,再加上一个队列 k e y n u m k e y n u m 的每一位应该和 q 的每一位两两对应。 k e y n u m 储存的是到达这个状态的时候的钥匙压缩后的数字
那么当我们决定要走这条路的时候,除了 S P F A 本身的距离判断,还要再加上一个现在拥有的钥匙是否可以走这条路的判断。我们知道,如果可以走这条路,那么就必须拥有开启这条路的钥匙,所以就有 n u m & a m p ; e [ i ] . k e y = e [ i ] . k e y
最后枚举到达终点时的钥匙,并输出最小值即可。


代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/82713795