JZOJ 5459. 【NOIP2017提高A组冲刺11.7】密室

来源:互联网 发布:百度数据研发部 编辑:程序博客网 时间:2024/05/29 06:57

题目大意

有n个节点m条边,里面有一些不同种类钥匙。如果要通过一条边,需要有特定种类的钥匙(多把)。问最少要经过几条边从1走到n。
数据范围
n≤5000,m≤6000,钥匙的种类k≤10。

题解

条件:
①要求通过一条边有特定种类的钥匙。
②经过的边数最少。
特定的种类?时间复杂度肯定含有2^k,再套什么最短路算法比如spfa。
直接状压DP!!!
但是为什么时间超限?我蠢。
由于队列里已经记录了点x和具备钥匙的状态s,直接拿它去更新其他状态就好了,不必枚举冗余状态

错误代码(TLE)

while(H<T){    H++;    x=qu[H][0];    kk=qu[H][1];    for(i=head[x];i;i=edge[i].next){        fo(s,0,_2[k+1]-1){            v=s|a[x];            if((v|edge[i].val)!=v)continue;            if(f[edge[i].to][v]>f[x][s]+1){                f[edge[i].to][v]=f[x][s]+1;                if(!bz[edge[i].to][v]){                    bz[edge[i].to][v]=1;                    qu[++T][0]=edge[i].to;                    qu[T][1]=v;                }            }        }    }    bz[x][kk]=0;}

这个代码的缺点:
①枚举大量冗余状态。
②有松弛操作。

但是这道题目不需要松弛操作,因为第一次更新的解一定是状态的最优解。
所以bfs就好了。

总结

①对于spfa,如果已经有二进制的状态,就不必枚举代表意义相同的二进制状态

代码

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#define N 5010#define M 6010#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;struct note{    int to,next,val;};note edge[M];int head[N],tot;int f[N][1030];int i,j,k,ans,n,m,x,kk,temp;int u,v,H,T,s;long long sum,cnt;int _2[12];int a[N];int qu[N*3030][2];void lb(int x,int y,int z){    edge[++tot].to=y;    edge[tot].next=head[x];    edge[tot].val=z;    head[x]=tot;}int main(){    freopen("room.in","r",stdin);    freopen("room.out","w",stdout);    _2[1]=1;fo(i,2,11)_2[i]=_2[i-1]*2;    scanf("%d%d%d",&n,&m,&k);    fo(i,1,n){        a[i]=0;        fo(j,1,k){            scanf("%d",&x);            a[i]+=_2[j]*x;        }    }    fo(i,1,m){        scanf("%d%d",&u,&v);        temp=0;        fo(j,1,k){            scanf("%d",&x);            temp+=_2[j]*x;        }        lb(u,v,temp);    }    memset(f,63,sizeof(f));    f[1][a[1]]=0;    H=0,T=1;    qu[1][0]=1;    qu[1][1]=a[1];    while(H<T){        H++;        x=qu[H][0];kk=qu[H][1];        for(i=head[x];i;i=edge[i].next){            if((kk|edge[i].val)!=kk)continue;            v=kk|a[edge[i].to];            if(f[edge[i].to][v]==1061109567){                f[edge[i].to][v]=f[x][kk]+1;                qu[++T][0]=edge[i].to;                qu[T][1]=v;            }        }    }    ans=1061109567;    fo(i,0,_2[k+1]-1)ans=min(ans,f[n][i]);    if(ans==1061109567)printf("No Solution");else    printf("%d",ans);    return 0;}
阅读全文
1 0
原创粉丝点击