孤岛营救与汽车加油行驶问题
题目链接:https://www.luogu.org/problemnew/show/P4011 (孤岛营救)|| https://www.luogu.org/problemnew/show/P4009 (汽车加油行驶)
题解:
两道分层图,所以我放在一起了=-=
别人都是对状态直接bfs了,我是对每个状态编号、建图,然后跑spfa。(感觉直接bfs好像会快一点,找时间学习一波qwq)
关于编号的注意事项就是不同点的编号一定不能重复,不然就会出现各种奇奇怪怪的错误。(血的教训啊...)
孤岛营救:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<bitset> 6 #define LL long long 7 #define RI register int 8 using namespace std; 9 const int INF = 0x7ffffff ; 10 const int N = 10 + 2 ; 11 const int CC = 100 + 10 ; 12 const int M = 1e6 + 10 ; 13 const int NN = 1e6 + 10 ; 14 15 const int cx[] = {-1,0,0,1} ; 16 const int cy[] = {0,1,-1,0} ; 17 18 inline int read() { 19 int k = 0 , f = 1 ; char c = getchar() ; 20 for( ; !isdigit(c) ; c = getchar()) 21 if(c == '-') f = -1 ; 22 for( ; isdigit(c) ; c = getchar()) 23 k = k*10 + c-'0' ; 24 return k*f ; 25 } 26 struct Edge { 27 int to, next, val ; 28 }e[M] ; 29 int n, m, p, k, t ; int head[NN], dis[NN] ; 30 int noo[N][N][N][N] ; // 11表示墙,其他数字表示钥匙 31 inline void add_edge(int x,int y,int vv) { 32 static int cnt = 1 ; 33 e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt, e[cnt].val = vv ; 34 } 35 36 inline void spfa() { 37 for(int i=1;i<=NN;i++) dis[i] = INF ; int s = 1 ; 38 deque<int>q ; q.push_back(s) ; dis[s] = 0 ; bitset<NN>inq ; 39 while(!q.empty()) { 40 int x = q.front() ; q.pop_front() ; 41 for(int i=head[x];i;i=e[i].next) { 42 int y = e[i].to ; 43 if(dis[y] > dis[x]+e[i].val) { 44 dis[y] = dis[x]+e[i].val ; 45 if(!inq[y]) { 46 if(!q.empty() && dis[y] < dis[q.front()]) q.push_front(y) ; 47 else q.push_back(y) ; 48 inq[y] = 1 ; 49 } 50 } 51 } 52 inq[x] = 0 ; 53 } 54 if(dis[t] == INF) printf("-1") ; 55 else printf("%d",dis[t]) ; 56 } 57 58 int main() { 59 n = read(), m = read(), p = read(), k = read() ; t = NN-10 ; 60 int x1, y1, x2, y2, ii ; 61 for(int i=1;i<=k;i++) { 62 x1 = read(), y1 = read(), x2 = read(), y2 = read(), ii = read() ; 63 if(!ii) { 64 noo[x1][y1][x2][y2] = noo[x2][y2][x1][y1] = 11 ; 65 } else noo[x1][y1][x2][y2] = noo[x2][y2][x1][y1] = ii ; 66 } 67 for(int s=0;s<(1<<p);s++) { 68 for(int i=1;i<=n;i++) { 69 for(int j=1;j<=m;j++) { 70 int p = s*CC + (i-1)*m + j ; 71 for(int k=0;k<4;k++) { 72 int xx = i+cx[k], yy = j+cy[k] ; 73 if(!xx || !yy || xx > n || yy > m) continue ; 74 int pp = s*CC + (xx-1)*m + yy ; 75 if( !noo[i][j][xx][yy] || (s&(1<<(noo[i][j][xx][yy]-1))) ) 76 add_edge(p,pp,1), add_edge(pp,p,1) ; 77 } 78 } 79 } 80 } 81 int nn = read() ; 82 for(int i=1;i<=nn;i++) { 83 int x = read(), y = read(), kk = read() ; 84 for(int s=0;s<(1<<p);s++) { 85 if(!(s&(1<<(kk-1)))) { // 没有该钥匙的状态可以转移到有该钥匙的状态 86 int p1 = s*CC + (x-1)*m + y, p2 = (s^(1<<(kk-1)))*CC + (x-1)*m + y ; 87 add_edge(p1,p2,0) ; 88 } 89 } 90 } 91 for(int s=0;s<(1<<p);s++) add_edge(s*CC+n*m,t,0) ; 92 spfa() ; 93 return 0 ; 94 }
汽车加油行驶:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<bitset> 6 #define LL long long 7 #define RI register int 8 using namespace std; 9 const int INF = 0x7ffffff ; 10 const int CC = 1e4 + 100 ; 11 const int N = 100 + 10 ; 12 const int NN = 1e6 + 10 ; 13 const int M = 1e6 + 10 ; 14 15 const int cx1[] = {-1,0} ; 16 const int cy1[] = {0,-1} ; 17 const int cx2[] = {1,0} ; 18 const int cy2[] = {0,1} ; 19 20 inline int read() { 21 int k = 0 , f = 1 ; char c = getchar() ; 22 for( ; !isdigit(c) ; c = getchar()) 23 if(c == '-') f = -1 ; 24 for( ; isdigit(c) ; c = getchar()) 25 k = k*10 + c-'0' ; 26 return k*f ; 27 } 28 struct Edge { 29 int to, next, val ; 30 }e[M] ; 31 int n, k, a, b, c, s, t ; int head[NN], dis[NN] ; 32 bool hh[N][N] ; 33 inline void add_edge(int x,int y,int vv) { 34 static int cnt = 0 ; 35 e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt, e[cnt].val = vv ; 36 } 37 38 inline void spfa() { 39 for(int i=1;i<=NN;i++) dis[i] = INF ; 40 deque<int>q ; q.push_back(s) ; dis[s] = 0 ; bitset<NN>inq ; inq[s] = 1 ; 41 while(!q.empty()) { 42 int x = q.front() ; q.pop_front() ; 43 for(int i=head[x];i;i=e[i].next) { 44 int y = e[i].to ; 45 if(dis[y] > dis[x]+e[i].val) { 46 dis[y] = dis[x]+e[i].val ; 47 if(!inq[y]) { 48 inq[y] = 1 ; 49 if(!q.empty() && dis[y] < dis[q.front()]) q.push_front(y) ; 50 else q.push_back(y) ; 51 } 52 } 53 } 54 inq[x] = 0 ; 55 } 56 printf("%d",dis[t]) ; 57 } 58 59 int main() { 60 // freopen("trav.in","r",stdin) ; 61 // freopen("trav.out","w",stdout) ; 62 n = read(), k = read(), a = read(), b = read(), c = read() ; t = (k+1)*CC + 10 ; 63 for(int i=1;i<=n;i++) 64 for(int j=1;j<=n;j++) hh[i][j] = read() ; 65 for(int now=k;now;now--) { 66 for(int i=1;i<=n;i++) { 67 for(int j=1;j<=n;j++) { 68 if(!hh[i][j]) { // 无加油站 69 for(int kk=0;kk<2;kk++) { 70 int xx = i+cx1[kk], yy = j+cy1[kk] ; 71 if(!xx || !yy || xx > n || yy > n) continue ; 72 add_edge(now*CC+(i-1)*n+j,(now-1)*CC+(xx-1)*n+yy,b) ; 73 } 74 for(int kk=0;kk<2;kk++) { 75 int xx = i+cx2[kk], yy = j+cy2[kk] ; 76 if(!xx || !yy || xx > n || yy > n) continue ; 77 add_edge(now*CC+(i-1)*n+j,(now-1)*CC+(xx-1)*n+yy,0) ; 78 } 79 } else { // 有加油站 80 for(int kk=0;kk<2;kk++) { 81 int xx = i+cx1[kk], yy = j+cy1[kk] ; 82 if(!xx || !yy || xx > n || yy > n) continue ; 83 add_edge(now*CC+(i-1)*n+j,(k-1)*CC+(xx-1)*n+yy,b+a) ; 84 } 85 for(int kk=0;kk<2;kk++) { 86 int xx = i+cx2[kk], yy = j+cy2[kk] ; 87 if(!xx || !yy || xx > n || yy > n) continue ; 88 add_edge(now*CC+(i-1)*n+j,(k-1)*CC+(xx-1)*n+yy,a) ; 89 } 90 } 91 // 创造加油站 =-= 92 for(int kk=0;kk<2;kk++) { 93 int xx = i+cx1[kk], yy = j+cy1[kk] ; 94 if(!xx || !yy || xx > n || yy > n) continue ; 95 add_edge(now*CC+(i-1)*n+j,(k-1)*CC+(xx-1)*n+yy,a+b+c) ; 96 } 97 for(int kk=0;kk<2;kk++) { 98 int xx = i+cx2[kk], yy = j+cy2[kk] ; 99 if(!xx || !yy || xx > n || yy > n) continue ; 100 add_edge(now*CC+(i-1)*n+j,(k-1)*CC+(xx-1)*n+yy,a+c) ; 101 } 102 } 103 } 104 } 105 for(int i=1;i<=n;i++) 106 for(int j=1;j<=n;j++) { 107 if(!hh[i][j]) { 108 for(int kk=0;kk<2;kk++) { 109 int xx = i+cx1[kk], yy = j+cy1[kk] ; 110 if(!xx || !yy || xx > n || yy > n) continue ; 111 add_edge(n*(i-1)+j,(k-1)*CC+(xx-1)*n+yy,c+b+a) ; 112 } 113 for(int kk=0;kk<2;kk++) { 114 int xx = i+cx2[kk], yy = j+cy2[kk] ; 115 if(!xx || !yy || xx > n || yy > n) continue ; 116 add_edge(n*(i-1)+j,(k-1)*CC+(xx-1)*n+yy,c+a) ; 117 } 118 } else { 119 for(int kk=0;kk<2;kk++) { 120 int xx = i+cx1[kk], yy = j+cy1[kk] ; 121 if(!xx || !yy || xx > n || yy > n) continue ; 122 add_edge(n*(i-1)+j,(k-1)*CC+(xx-1)*n+yy,b+a) ; 123 } 124 for(int kk=0;kk<2;kk++) { 125 int xx = i+cx2[kk], yy = j+cy2[kk] ; 126 if(!xx || !yy || xx > n || yy > n) continue ; 127 add_edge(n*(i-1)+j,(k-1)*CC+(xx-1)*n+yy,a) ; 128 } 129 } 130 } 131 for(int now=k;now>=0;now--) add_edge(now*CC+n*n,t,0) ; s = k*CC + 1 ; 132 spfa() ; 133 return 0 ; 134 }