\(\\\)

\(Description\)


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

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

现在可以开发任意个数的空地变为落脚点,问找到合法路径最少需要开发多少个空地,在满足第一个条件下最少移动多少步,在满足前两个条件下有多少条不同的路径。

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

\(\\\)

\(Solution\)


被上一个题干蒙直接\(NC\)......我还说Silver咋比Gold还难

这题.......仔细读题之后错觉是\(Gold\)那题再加上一层限制的最短路,后来发现不是.......

仔细读题,注意这次的方案数不再是放置落脚点的方案,而是路径数。

那么我们就不必考虑选择不同原有落脚点导致方案同构的尴尬情况了,直接将每一个点向一步可以到达的点建边,如果是从空地向外建边代价为\(1\),其他为\(0\)即可。

最短路计数时有双层限制,注意讨论更新的情况。

\(\\\)

\(Code\)


#include<cmath>
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 50
#define M 60010
#define R register
#define gc getchar
#define inf 9000000000000000ll
using namespace std;
typedef long long ll; inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
} bool vis[N*N]; const int dx[8]={1,1,-1,-1,2,2,-2,-2}; const int dy[8]={2,-2,2,-2,1,-1,1,-1}; ll ts[N*N],stp[N*N],dis[N*N];
int n,m,s,t,tot,cnt,num[N][N],mp[N][N],hd[N*N]; struct edge{int w,to,nxt;}e[M<<1]; inline void add(int u,int v,int w){
e[++tot].to=v; e[tot].w=w;
e[tot].nxt=hd[u]; hd[u]=tot;
} inline void make(int ux,int uy){
for(R int i=0,nx,ny;i<8;++i){
nx=ux+dx[i]; ny=uy+dy[i];
if(nx<1||nx>n||ny<1||ny>m) continue;
add(num[ux][uy],num[nx][ny],mp[ux][uy]==0);
}
} queue<int> q; inline void SPFA(){
memset(vis,0,sizeof(vis));
memset(stp,0x3f,sizeof(stp));
for(R int i=1;i<=cnt;++i) dis[i]=inf;
q.push(s); dis[s]=0;
ts[s]=1ll; stp[s]=0;
while(!q.empty()){
int u=q.front();
q.pop(); vis[u]=0;
for(R int i=hd[u],v;i;i=e[i].nxt)
if(dis[v=e[i].to]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
stp[v]=stp[u]+1; ts[v]=ts[u];
if(!vis[v]) vis[v]=1,q.push(v);
}
else if(dis[v]==dis[u]+e[i].w&&stp[v]>stp[u]+1){
stp[v]=stp[u]+1; ts[v]=ts[u];
if(!vis[v]) vis[v]=1,q.push(v);
}
else if(dis[v]==dis[u]+e[i].w&&stp[v]==stp[u]+1) ts[v]+=ts[u];
}
} int main(){
n=rd(); m=rd();
for(R int i=1;i<=n;++i)
for(R int j=1;j<=m;++j){
mp[i][j]=rd();
num[i][j]=++cnt;
if(mp[i][j]==3) s=cnt;
if(mp[i][j]==4) t=cnt;
}
for(R int i=1;i<=n;++i)
for(R int j=1;j<=m;++j)
if(mp[i][j]!=2) make(i,j);
SPFA();
if(dis[t]<inf) printf("%lld\n%lld\n%lld\n",dis[t],stp[t],ts[t]);
else puts("-1");
return 0;
}

最新文章

  1. Linux基础练习题(三)
  2. 使用Nginx镜像代理.NET Core MVC
  3. Comet服务器推送与SignalR
  4. 帝国cms栏目自定义字段首页调用
  5. React组件
  6. centos上手动编译安装tmux的问题
  7. [Effective JavaScript 笔记]第34条:在原型中存储方法
  8. 寒冰王座[HDU1248]
  9. R语言putty中直接使用X11(Xming)绘图
  10. JS操作DOM常用API总结
  11. [原]POJ-1631-Bridging signals-( 水LIS-O(nlogn) -DP)
  12. POJ 1170 Shopping Offers -- 动态规划(虐心的六重循环啊!!!)
  13. partial修饰符,可以让同类命名空间下出现重名
  14. Objective-c开发教程--MRC和ARC混编
  15. Android GPS应用:动态获取位置信息
  16. mac 下nginx加入开机启动
  17. Oracle获取时间日期月份星期数
  18. python之栈和队列
  19. Jasperreport5.6.9-----2
  20. Sqlserver 2008 R2安装的盘符空间不够用的解决办法

热门文章

  1. JSP操作
  2. java STW stop the world 哈哈就是卡住了
  3. ubuntu Install Firefox
  4. VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群—整合Zookeeper和Hbase
  5. Windows 老是弹出要自动拨号连接怎么办
  6. iOS音频播放 (二):AudioSession 转
  7. CLR-基元类型以及溢出检查 (CLR-Via-C#) 类型基础
  8. 【面试】iOS 开发面试题(一)
  9. 多个client与一个server端通信的问题
  10. “取出数据表中第10条到第20条记录”的sql语句+select top 使用方法