\(\\\)

\(Description\)


一张\(N\times M\)的网格,已知起点和终点,其中有一些地方是落脚点,有一些地方是空地,还有一些地方是坏点。

现在要从起点到终点,每次移动走日字\((\)横一纵二或横二纵一\()\),其中只能经过起点、终点、落脚点。

现在可以开发任意个数的空地变为落脚点,问找到合法路径最少需要开发多少个空地,以及最少开发的方案数。

注意,只要有一个被开发的空地不同即视为不同的方案。

  • \(N,M\in [1,30]\)

\(\\\)

\(Solution\)


不得不说建图相当妙。

先考虑一种直接的建图方式,落脚点和起点向可以直接到达的空地或落脚点连\(0\)边,空地向可以直接到达的空地或落脚点连\(1\)边,最短路计数。我们发现这样的最短路长度是没有问题的,但是最短路方案数是有问题的。

因为像这样,在两个空地之间可以有多个可以用于转移的原有落脚点时,方案数就会多算好几倍。

\(\\\)

然后发现,貌似中间经过已有的落脚点不同并不会影响两点间的最短路长度和计数,所以不妨直接忽略掉所有原有的落脚点以及坏点,只考虑包含起点、终点、空地的图,以下将起点终点视为空地。

建图可以对每一个合法的点\(BFS\)一遍,统计出该点在经过若干个\((\)可以不经过\()\)原有落脚点可以到达的空地,显然中间经过落脚点是没有代价的,而在开始\(BFS\)的点处需要花费代价建造落脚点,所以边权为\(1\)。特殊的,起点并不需要代价,所以起点连出去的边边权为\(0\)。此时最短路条数显然就是方案数了。

\(\\\)

\(Code\)


最短路计数又傻了....注意不是加一而是累加,以及重置的时候不是\(1\),而是直接继承

注意边表的大小需要开 long long 差评

  1. #include<cmath>
  2. #include<queue>
  3. #include<cctype>
  4. #include<cstdio>
  5. #include<cstring>
  6. #include<cstdlib>
  7. #include<iostream>
  8. #include<algorithm>
  9. #define N 50
  10. #define M 60010
  11. #define R register
  12. #define gc getchar
  13. #define inf 200000000
  14. using namespace std;
  15. typedef long long ll;
  16. inline int rd(){
  17. int x=0; bool f=0; char c=gc();
  18. while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  19. while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  20. return f?-x:x;
  21. }
  22. bool vis[N*N];
  23. const int dx[8]={1,1,-1,-1,2,2,-2,-2};
  24. const int dy[8]={2,-2,2,-2,1,-1,1,-1};
  25. ll ts[N*N];
  26. int n,m,s,t,tot,dis[N*N];
  27. int cnt,num[N][N],mp[N][N],hd[N*N];
  28. struct edge{int w,to,nxt;}e[M<<1];
  29. inline void add(int u,int v,int w){
  30. e[++tot].to=v; e[tot].w=w;
  31. e[tot].nxt=hd[u]; hd[u]=tot;
  32. }
  33. queue<pair<int,int> > q;
  34. inline void bfs(int ux,int uy,int w){
  35. memset(vis,0,sizeof(vis));
  36. q.push(make_pair(ux,uy)); vis[num[ux][uy]]=1;
  37. while(!q.empty()){
  38. int x=q.front().first;
  39. int y=q.front().second; q.pop();
  40. for(R int i=0,nx,ny;i<8;++i){
  41. nx=x+dx[i]; ny=y+dy[i];
  42. if(nx<1||nx>n||ny<1||ny>m||vis[num[nx][ny]]) continue;
  43. vis[num[nx][ny]]=1;
  44. if(mp[nx][ny]!=1&&mp[nx][ny]!=2) add(num[ux][uy],num[nx][ny],w);
  45. else if(mp[nx][ny]==1) q.push(make_pair(nx,ny));
  46. }
  47. }
  48. }
  49. queue<int> qs;
  50. inline void SPFA(){
  51. memset(vis,0,sizeof(vis));
  52. for(R int i=1;i<=cnt;++i) dis[i]=inf;
  53. qs.push(s); dis[s]=0; ts[s]=1ll;
  54. while(!qs.empty()){
  55. int u=qs.front();
  56. qs.pop(); vis[u]=0;
  57. for(R int i=hd[u],v;i;i=e[i].nxt)
  58. if(dis[v=e[i].to]>dis[u]+e[i].w){
  59. dis[v]=dis[u]+e[i].w; ts[v]=ts[u];
  60. if(!vis[v]) vis[v]=1,qs.push(v);
  61. }
  62. else if(dis[v]==dis[u]+e[i].w) ts[v]+=ts[u];
  63. }
  64. }
  65. int main(){
  66. n=rd(); m=rd();
  67. for(R int i=1;i<=n;++i)
  68. for(R int j=1;j<=m;++j){
  69. mp[i][j]=rd();
  70. num[i][j]=++cnt;
  71. if(mp[i][j]==3) s=cnt;
  72. if(mp[i][j]==4) t=cnt;
  73. }
  74. for(R int i=1;i<=n;++i)
  75. for(R int j=1;j<=m;++j)
  76. if(mp[i][j]==0||mp[i][j]>1) bfs(i,j,(mp[i][j]!=3));
  77. SPFA();
  78. if(dis[t]<inf) printf("%d\n%lld",dis[t],ts[t]);
  79. else puts("-1");
  80. return 0;
  81. }

[ USACO 2007 FEB ] Lilypad Pond (Gold)的更多相关文章

  1. [ USACO 2007 FEB ] Lilypad Pond (Silver)

    \(\\\) \(Description\) 一张\(N\times M\)的网格,已知起点和终点,其中有一些地方是落脚点,有一些地方是空地,还有一些地方是坏点. 现在要从起点到终点,每次移动走日字\ ...

  2. BZOJ 1632: [Usaco2007 Feb]Lilypad Pond

    题目 1632: [Usaco2007 Feb]Lilypad Pond Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 390  Solved: 109[ ...

  3. 1632: [Usaco2007 Feb]Lilypad Pond

    1632: [Usaco2007 Feb]Lilypad Pond Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 404  Solved: 118[Sub ...

  4. 「BZOJ 1698」「USACO 2007 Feb」Lilypad Pond 荷叶池塘「最短路」

    题解 从一个点P可以跳到另一个点Q,如果Q是水这条边就是1,如果Q是荷叶这条边权值是0.可以跑最短路并计数 问题是边权为0的最短路计数没有意义(只是荷叶的跳法不同),所以我们两个能通过荷叶间接连通的点 ...

  5. bzoj1632 [Usaco2007 Feb]Lilypad Pond

    Description Farmer John 建造了一个美丽的池塘,用于让他的牛们审美和锻炼.这个长方形的池子被分割成了 M 行和 N 列( 1 ≤ M ≤ 30 ; 1 ≤ N ≤ 30 ) 正方 ...

  6. BZOJ1632: [Usaco2007 Feb]Lilypad Pond SPFA+最短路计数

    Description 为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘.这个长方形的池子被分成了M行N列个方格(1≤M,N≤30).一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是 ...

  7. 【BZOJ】1632: [Usaco2007 Feb]Lilypad Pond(bfs)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1632 我简直是个sb... ... bfs都不会写.. 算方案还用2个bfs! 都不会整合到一个! ...

  8. BZOJ 1632 [Usaco2007 Feb]Lilypad Pond:spfa【同时更新:经过边的数量最小】【路径数量】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1632 题意: 有一个n*m的池塘.0代表水,1代表荷花,2代表岩石,3代表起点,4代表终点 ...

  9. BZOJ1698: [Usaco2007 Feb]Lilypad Pond 荷叶池塘

    一傻逼题调了两天.. n<=30 * m<=30的地图,0表示可以放平台,1表示本来有平台,2表示不能走,3起点4终点,走路方式为象棋的日字,求:从起点走到终点,至少要放多少平台,以及放平 ...

随机推荐

  1. echarts模拟highcharts实现折线图的虚实转换

    多的不说直接上代码: <html><html lang="en"><head> <meta charset="utf-8&quo ...

  2. ThinkPHP3.2 点击看不清刷新验证码

    欢迎使用Markdown编辑器写博客 baidu了一下.发现没有可用的源码,自己想了想,以下的方法可行. <!DOCTYPE html> <html> <head> ...

  3. chassis & power

    机箱电源 ★ Main board ★ Voltage, connector ★ Hole ★ Ports ★ AT:12``*13.8`` or 12``*13``  30.5cm*33cm ★ B ...

  4. Spring MVC的简单使用方法

    一.Multiaction Controller package cn.framelife.mvc.control; import org.springframework.stereotype.Con ...

  5. Vue.js 组件的三个 API:prop、event、slot

    组件的构成 一个再复杂的组件,都是由三部分组成的:prop.event.slot,它们构成了 Vue.js 组件的 API.如果你开发的是一个通用组件,那一定要事先设计好这三部分,因为组件一旦发布,后 ...

  6. 图像处理之基础---基于opencv的灰度图像微分

    argv分别为,可执行文件名.读入的原始图像.输出原始图像的灰度值.输出原始图像灰度值沿x轴方向的一阶微分.输出原始图像灰度值沿x轴方向的二阶微分. #include #include #includ ...

  7. [办公自动化]计算机突然死机后asd自动恢复文档未能恢复,如何打开使用

    今天计算机突然死机,但是word未能提示自动恢复窗格.所以无法自动恢复word文档.但是在文档所在的文件夹看到了一个“自动恢复”开头的asd恢复文档. 该如何使用这个文档呢? 按照以前的惯例,尝试了如 ...

  8. HDU 5416

    CRB and Tree                                       Time Limit: 8000/4000 MS (Java/Others)    Memory ...

  9. 什么是sibling and tail recursive calls

    1 tail call 在函数f中调用函数b,如果这个调用是函数f中执行的最后一条指令,那么这个调用就称为tail call. 例子: int foo(float a, float b) { ... ...

  10. openstack dnsmasq调试