zoukankan      html  css  js  c++  java
  • 【洛谷4011】孤岛营救问题(状压SPFA)

    点此看题面

    大致题意: 有一个(N*M)的四联通迷宫,相邻两个可能互通,可能有一扇门,也可能有一堵墙。对于第(i)类的门,你需要有第(i)类的钥匙才可以通过。问你从((1,1))到达((N,M))的最短路。

    第一步:建图

    看到种类数(≤10),应该不难想到状压吧!而且,我们还可以给每个格子一个编号(计算方法:(pos(x,y)=(x-1)*m+y))。

    我们可以用(key_i)来表示编号为(i)的格子上有的钥匙状压之后的结果,并用(dis_{i,j})来表示从((1,1))出发,到达编号为(i)的节点时拥有的钥匙种类状压之后的结果为(j)的最短路径。

    接下来,我们可以枚举每一个节点(i)与其一个相邻的节点(j),然后分类讨论:

    • 如果它们互通:在它们之间建一条边权为1的边。
    • 如果它们之间有一扇门:假设这扇门的种类为(x),就在他们之间建一条边权为(2^x)的边。
    • 如果它们之间有一堵墙:不建边。

    其中,边权就相当于走这条边的条件,一定要当前拥有的钥匙含有开启这扇门的钥匙才行。

    第二步:跑最(wang)短(luo)路(liu)

    建完了图,就可以开始跑最短路了,当然,这题作为网络流24题之一,你一定要写网络流也没人拦你

    一开始初始化拥有的钥匙状压后的结果为1(不然就无法过边权为1的边),然后,每到达一个节点,就可以更新拥有的钥匙后的状压结果了。

    最短路的过程应该还是比较简单的,这题难就难在建图。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define abs(x) ((x)<0?-(x):(x))
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
    #define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
    #define N 10
    #define pos(x,y) ((x-1)*m+y)
    #define add(x,y,z) (e[++ee].to=y,e[ee].nxt=lnk[x],e[lnk[x]=ee].val=z)
    int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
    using namespace std;
    int n,m,s,ans=1e9,ee=0,Inqueue[N*N+5][1<<N+1],dis[N*N+5][1<<N+1],lnk[N*N+5],keys[N*N+5],f[N*N+5][N*N+5];
    struct edge
    {
        int to,nxt,val;
    }e[((N*N)<<2)+5];
    struct Status
    {
        int x,v;
    }q[((N*N)<<N+1)+5];
    inline void read(int &x)
    {
        x=0;int f=1;static char ch;
        while(!isdigit(ch=tc())) f=ch^'-'?1:-1;
        while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
        x*=f;
    }
    inline void write(int x)
    {
        if(x<0) pc('-'),x=-x;
        if(x>9) write(x/10);
        pc(x%10+'0');
    }
    inline void SPFA()//跑最短路
    {
        register int i,j,H=Inqueue[1][1]=1,T=1,maxx=1<<s+1,MOD=(N*N)<<N+1;register Status k;q[1]=(Status){1,1};
        for(i=1;i<=n*m;++i) for(j=0;j<maxx;++j) dis[i][j]=1e9;dis[1][1]=0;
        while((H%=MOD)^(T+1))//只要队列没有空
        {
            k=q[H++],Inqueue[k.x][k.v]=0,dis[k.x][k.v|keys[k.x]]=min(dis[k.x][k.v|keys[k.x]],dis[k.x][k.v]),k.v|=keys[k.x];//更新当前拥有的钥匙的数量
            for(i=lnk[k.x];i;i=e[i].nxt)//枚举当前节点能到达的每一个节点
            {
                if((k.v&e[i].val)^e[i].val) continue;//如果不满足条件,就跳过
                if(dis[k.x][k.v]+1<dis[e[i].to][k.v])//如果更短就更新最短距离 
                {
                    dis[e[i].to][k.v]=dis[k.x][k.v]+1;
                    if(!Inqueue[e[i].to][k.v]) Inqueue[e[i].to][k.v]=1,q[(++T)%=MOD]=(Status){e[i].to,k.v};//如果不在队列中,就将其加入队列
                }
            }
        }
        for(i=0;i<maxx;++i) ans=min(ans,dis[n*m][i]);//求出最优的答案
    }
    int main()
    {
        register int i,j,t,x,y,z;
        for(read(n),read(m),read(s),i=1;i<=n*m;++i) for(j=1;j<=n*m;++j) f[i][j]=-1;
        for(read(t);t;--t)
        {
            static int u,v;
            read(x),read(y),u=pos(x,y),read(x),read(y),v=pos(x,y),read(x),f[u][v]=f[v][u]=x;
            if(x) add(u,v,1<<f[u][v]),add(v,u,1<<f[u][v]);//如果这不是一堵墙,就新建一条边
        }
        for(i=1;i<=n;++i)
        {
            for(j=1;j<=m;++j)
            {
    	        //对于互通的情况建边
                if(i>1&&!(~f[pos(i,j)][pos(i-1,j)])) add(pos(i,j),pos(i-1,j),1);
                if(i<n&&!(~f[pos(i,j)][pos(i+1,j)])) add(pos(i,j),pos(i+1,j),1);
                if(j>1&&!(~f[pos(i,j)][pos(i,j-1)])) add(pos(i,j),pos(i,j-1),1);
                if(j<m&&!(~f[pos(i,j)][pos(i,j+1)])) add(pos(i,j),pos(i,j+1),1);
            }
        }
        for(read(t);t;--t) read(x),read(y),read(z),keys[pos(x,y)]|=1<<z;//读入每一把钥匙,更新每一个位置的钥匙种类状压后的值
        return SPFA(),write(ans^1000000000?ans:-1),fwrite(pp,1,pp_,stdout),0;
    }
    
  • 相关阅读:
    编码转换,基础补充,深浅拷贝,id is == ,代码块(了解),小数据池(了解)
    字典(dict),字典的嵌套,集合(set)
    列表,列表的增删改查,列表的嵌套,range
    整数,布尔值,字符串,字符串详解.
    [小明学Shader]4.自定义光照----RampTexture
    [小明学Shader]3.自定义光照,半拉姆伯特
    [小明学Shader]2.理解Shader和Material的关系
    [小明学Shader]1.Diffuse
    [UGUI]你说UnityEngine.UI.Button是怎么通过拖动来增加OnClick的监听器的呢?
    [小明也得懂架构]1.架构初探
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4011.html
Copyright © 2011-2022 走看看