孤岛营救与汽车加油行驶问题

  题目链接: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 }
原文地址:https://www.cnblogs.com/zub23333/p/8697201.html