BZOJ 1632 [Usaco2007 Feb]Lilypad Pond:spfa【同時更新:經過邊的數量最小】【路徑數量】
題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1632
題意:
有一個n*m的池塘。0代表水,1代表荷花,2代表巖石,3代表起點,4代表終點。
Bessie在練芭蕾舞,她要從起點跳到終點去。
她只能走“日”字形,並且只能跳到荷花上。
荷花不能長在巖石上。
問你:
(1)至少要再添加多少個荷花,才能使Bessie可以跳到終點。
(2)在(1)的前提下,讓Bessie跳到終點的步數最小,並輸出。
(3)在(1)(2)條件下的路徑條數。
題解:
方便起見,對於每個點(x,y)可以表示成x*m+y的形式,即平面上的點在實數上的唯一映射。
第一問:
建圖。
對於每個點,到水建一條邊長為1的邊,到荷花建一條邊長為0的邊。
跑一邊spfa,第一問就出來了。
第二問:
在spfa中更新dis的時候,分兩種情況:
(1)dis[dest]==-1 || dis[dest]>dis[now]+len
此時dis被更新,相應的step[dest]一定要變成step[now]+1。
(2)dis[dest]==dis[now]+len
dis未被更新,但step有可能更優,step[dest] = min(step[dest], step[now]+1)
第三問:
在前兩問都不變的情況下,才有可能 cnt[dest] += cnt[now]。
否則cnt[dest] = cnt[now]
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #include <queue> 6 #define MAX_N 35 7 #define MAX_P 905 8 9 using namespacestd; 10 11 const int dx[]={-2,-2,-1,-1,1,1,2,2}; 12 const int dy[]={-1,1,-2,2,-2,2,-1,1}; 13 14 struct Edge 15 { 16 int dest; 17 int len; 18 Edge(int _dest,int _len) 19 { 20 dest=_dest; 21 len=_len; 22 } 23 Edge(){} 24 }; 25 26 int n,m; 27 int start,over; 28 int dis[MAX_P]; 29 int step[MAX_P]; 30 long long cnt[MAX_P]; 31 int a[MAX_N][MAX_N]; 32 bool vis[MAX_P]; 33 vector<Edge> edge[MAX_P]; 34 queue<int> q; 35 36 void read() 37 { 38 cin>>n>>m; 39 for(int i=0;i<n;i++) 40 { 41 for(int j=0;j<m;j++) 42 { 43 cin>>a[i][j]; 44 if(a[i][j]==3) start=i*m+j; 45 if(a[i][j]==4) over=i*m+j; 46 } 47 } 48 } 49 50 inline bool is_legal(int x,int y) 51 { 52 return x>=0 && x<n && y>=0 && y<m; 53 } 54 55 void build_graph() 56 { 57 for(int i=0;i<n;i++) 58 { 59 for(int j=0;j<m;j++) 60 { 61 for(int k=0;k<8;k++) 62 { 63 int x=i+dx[k]; 64 int y=j+dy[k]; 65 if(is_legal(x,y) && a[x][y]!=2) 66 { 67 edge[i*m+j].push_back(Edge(x*m+y,a[x][y]==0)); 68 } 69 } 70 } 71 } 72 } 73 74 int get_front() 75 { 76 int now=q.front(); 77 q.pop(); 78 vis[now]=false; 79 return now; 80 } 81 82 void insert(int now) 83 { 84 if(vis[now]) return; 85 q.push(now); 86 vis[now]=true; 87 } 88 89 void spfa(int start) 90 { 91 memset(dis,-1,sizeof(dis)); 92 memset(step,0x3f,sizeof(step)); 93 memset(cnt,0,sizeof(cnt)); 94 memset(vis,false,sizeof(vis)); 95 insert(start); 96 dis[start]=0; 97 step[start]=0; 98 cnt[start]=1; 99 while(!q.empty()) 100 { 101 int now=get_front(); 102 for(int i=0;i<edge[now].size();i++) 103 { 104 Edge temp=edge[now][i]; 105 if(dis[temp.dest]==-1 || dis[temp.dest]>dis[now]+temp.len) 106 { 107 dis[temp.dest]=dis[now]+temp.len; 108 step[temp.dest]=step[now]+1; 109 cnt[temp.dest]=cnt[now]; 110 insert(temp.dest); 111 } 112 else if(dis[temp.dest]==dis[now]+temp.len) 113 { 114 if(step[temp.dest]>step[now]+1) 115 { 116 step[temp.dest]=step[now]+1; 117 cnt[temp.dest]=cnt[now]; 118 insert(temp.dest); 119 } 120 else if(step[temp.dest]==step[now]+1) 121 { 122 cnt[temp.dest]+=cnt[now]; 123 insert(temp.dest); 124 } 125 } 126 } 127 } 128 } 129 130 void solve() 131 { 132 build_graph(); 133 spfa(start); 134 } 135 136 void print() 137 { 138 cout<<dis[over]<<endl; 139 if(dis[over]!=-1) 140 { 141 cout<<step[over]<<endl; 142 cout<<cnt[over]<<endl; 143 } 144 } 145 146 int main() 147 { 148 read(); 149 solve(); 150 print(); 151 }
BZOJ 1632 [Usaco2007 Feb]Lilypad Pond:spfa【同時更新:經過邊的數量最小】【路徑數量】