10.28T7 位运算+记忆化+DLZ常数剪枝
5170 -- 【11.05题目】密室
Description
小 X 正困在一个密室里,他希望尽快逃出密室。
密室中有 N 个房间,初始时,小 X 在 1 号房间,而出口在 N 号房间。
密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条从房间 X 到房间 Y 的通道。另外,想要通过某个传送门,就必须具备一些种类的钥匙(每种钥匙都要有才能通过)。幸运的是,钥匙在打开传送门的封印后,并不会消失。
然而,通过密室的传送门需要耗费大量的时间,因此,小 X 希望通过尽可能少的传送门到达出口,你能告诉小 X 这个数值吗?
另外,小 X 有可能不能逃出这个密室,如果是这样,请输出 "No Solution"。
密室中有 N 个房间,初始时,小 X 在 1 号房间,而出口在 N 号房间。
密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条从房间 X 到房间 Y 的通道。另外,想要通过某个传送门,就必须具备一些种类的钥匙(每种钥匙都要有才能通过)。幸运的是,钥匙在打开传送门的封印后,并不会消失。
然而,通过密室的传送门需要耗费大量的时间,因此,小 X 希望通过尽可能少的传送门到达出口,你能告诉小 X 这个数值吗?
另外,小 X 有可能不能逃出这个密室,如果是这样,请输出 "No Solution"。
Input
第一行三个整数 N,M,K,分别表示房间的数量、传送门的数量以及钥匙的种类数。
接下来 N 行,每行 K 个 0 或 1,若第 i 个数为 1,则表示该房间内有第 i 种钥匙,若第 i 个数为 0,则表示该房间内没有第 i 种钥匙。
接下来 M 行,每行先读入两个整数 X,Y,表示该传送门是建立在 X 号房间,通向 Y 号房间的,再读入 K 个 0 或 1,若第 i 个数为 1,则表示通过该传送门需要 i 种钥匙,若第 i 个数为 0,则表示通过该传送门不需要第 i 种钥匙。
接下来 N 行,每行 K 个 0 或 1,若第 i 个数为 1,则表示该房间内有第 i 种钥匙,若第 i 个数为 0,则表示该房间内没有第 i 种钥匙。
接下来 M 行,每行先读入两个整数 X,Y,表示该传送门是建立在 X 号房间,通向 Y 号房间的,再读入 K 个 0 或 1,若第 i 个数为 1,则表示通过该传送门需要 i 种钥匙,若第 i 个数为 0,则表示通过该传送门不需要第 i 种钥匙。
Output
输出一行一个 “No Solution”,或一个整数,表示最少通过的传送门数。
Sample Input
3 3 2
1 0
0 1
0 0
1 3 1 1
1 2 1 0
2 3 1 1
Sample Output
2
Hint
直接记忆化每个点在某个状态的值可以强力剪枝,如果直接爆搜直接爆栈,最后加上DLZ的5000000运算次数以上就剪掉就过了。。。
code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #define N 100000 6 using namespace std; 7 int tot; 8 struct node { 9 long long u,v,w; 10 } e[N]; 11 long long first[N],nxt[N],cnt,room[N]; 12 void add(long long u,long long v,long long w) { 13 e[++cnt].u=u; 14 e[cnt].v=v; 15 e[cnt].w=w; 16 nxt[cnt]=first[u]; 17 first[u]=cnt; 18 } 19 long long n,m,k; 20 long long min0=20020731; 21 int f[5001][2000]; 22 void dfs(long long x,long long now,long long step) { 23 tot++; 24 if(tot>=5000000)return; 25 if(step>=min0)return; 26 if(f[x][now]<=step)return; 27 f[x][now]=step; 28 if(x==n) { 29 min0=min(min0,step); 30 return; 31 } 32 for(long long i=first[x];i;i=nxt[i]){ 33 long long v=e[i].v; 34 if((now&e[i].w)!=e[i].w)continue; 35 long long temp=now|room[v]; 36 dfs(v,temp,step+1); 37 if(tot>=5000000)return; 38 } 39 } 40 long long read(){ 41 long long x=0,f=1; 42 char c=getchar(); 43 while(!isdigit(c)){ 44 if(c=='-')f=-1; 45 c=getchar(); 46 } 47 while(isdigit(c)){ 48 x=(x<<3)+(x<<1)+c-'0'; 49 c=getchar(); 50 } 51 return x*f; 52 } 53 int main() { 54 int siz=80<<20; 55 __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(siz)+siz)); 56 n=read(),m=read(),k=read(); 57 for(long long i=1; i<=n; i++) { 58 for(long long j=1; j<=k; j++) { 59 long long x; 60 x=read(); 61 room[i]=room[i]*2+x; 62 } 63 } 64 for(long long i=1; i<=m; i++) { 65 long long now=0; 66 long long a,b; 67 a=read(),b=read(); 68 for(long long j=1; j<=k; j++) { 69 long long x; 70 x=read(); 71 now=now*2+x; 72 } 73 add(a,b,now); 74 } 75 memset(f,0x3f3f3f3f,sizeof f); 76 dfs(1,room[1],0); 77 if(min0==20020731){ 78 cout<<"No Solution"; 79 } 80 else{ 81 cout<<min0; 82 } 83 exit(0); 84 return 0; 85 }
over