BZOJ 1632 [Usaco2007 Feb]Lilypad Pond:spfa同时更新:经过边的数量最小路径数量
Posted Leohh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 namespace std; 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同时更新:经过边的数量最小路径数量的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ1697][Usaco2007 Feb]Cow Sorting牛排序
bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序
BZOJ 1631: [Usaco2007 Feb]Cow Party
Bzoj 1696: [Usaco2007 Feb]Building A New Barn新牛舍 中位数,数学