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新牛舍 中位数,数学

BZOJ 1631 Usaco 2007 Feb. Cow Party

bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序置换群