做这题复习了几点
- bfs 预处理 ,因为判断某一点能不能走 ,需要提前对每个炮台进行预处理
- visit 数组 刚开始我想我这个 bfs 是从左上角遍历到右下角,不会回头,于是刚开始并不想构造 visit 数组。但是后来发现还是不太好,主要因为这题比较特别,
每个状态
有三个后继转移状态
,如下图,如果选择不走,那么接下来就可能会发生同一个状态多次入队的情况。
visit 数组也很好开,因为已经具有最大能量值,直接 visit[x][y][k]
三维数组开起来也不大。
但是我做题的时候没想到。
读题的时候比较费劲,我觉得这题题意比较模糊,大概就是
- 城堡会以一定的周期和速度向某个固定方向发射子弹。
- 城堡可以挡住到达该点的子弹。
- 城堡不能走
相当于闪点
在闪亮的时刻是不能走的。
满足如下公式,代表不能走
设某个城堡发射子弹的周期为 T,速度为 v,从起点到当前点的时间为 t, 当前点与城堡的距离是 s
如果满足 s = (t-k*t)*v
,则不能走。
但做这题的时候,我又犯蠢了。
我想用 一维vector 记录某个点所关联的所有子弹,但是我用 x * m+y 来定位某个点,这样会出现 3*4+4 = 4*4 + 0 = 16
两个不同的点,映射到同一个 index
,这样显然错误,于是我修改这个映射
#define mmm = 10005
用 x * mmm+y 来做映射,这样不会出现两个点映射到一个同一个索引的情况,学艺不精啊。
下附代码:
#include<iostream>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
#define mmm 10005
vector< vector<int> > num(1001000);
int m,n;
int maxp;
int k;
int maze[105][105];
char dirs[4]={'N','S','E','W'};
int ddi[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};
bool vis[105][105][1005];
struct cas
{
int t;
int v;
int dir;
int x;
int y;
};
cas castle[105];
int re;
struct point
{
int x;
int y;
int t;
};
queue<point>qu;
int dqu[3][2]={{1,0},{0,1},{0,0}};
void bfs()
{
memset(vis,0,sizeof(vis));
point st;
point f;
point next;
st.x=0;
st.y=0;
st.t=0;
while(!qu.empty())qu.pop();
qu.push(st);
while(!qu.empty())
{
f = qu.front();
// cout<<"***** "<<f.x<<" "<<f.y<<" "<<f.t<<endl;
qu.pop();
if(f.x==m&&f.y==n)
{
re = f.t;
break;
}
if(f.t > maxp)break;//如果已经大于能量值 就不用再算了
//向右走
//向下走
//停住不动
for(int i=0;i<3;i++)
{
int px =f.x+dqu[i][0];
int py =f.y+dqu[i][1];
if(px<0||py<0||px>m||py>n||maze[px][py]==-1||vis[px][py][f.t+1]==1)continue;
//判断是否有子弹
//cout<<"********************* "<<px<<" "<<py<<" "<<f.t+1<<endl;
int flag=1;
for(int j=0;j<num[px*mmm+py].size();j++)
{
int s = abs(px - castle[num[px*mmm+py][j]].x) + abs(py - castle[num[px*mmm+py][j]].y);
int a;
//cout<<"s = "<<s;
if(s%castle[num[px*mmm+py][j]].v==0)
{
a = s/castle[num[px*mmm+py][j]].v;
// cout<<" s/v 整除 "<<a<<endl;
}
else continue; //如果不整除 这个就不用算了
if((f.t+1)>=a&&(f.t+1 -a)%castle[num[px*mmm+py][j]].t==0) //如果该点有 子弹
{
// cout<<" t- T / a 整除"<<(f.t+1 -a)/castle[num[px*mmm+py][j]].t;
flag=0;
break;
}
// cout<<endl;
}
//cout<<endl;
if(flag==0)
{
//cout<<"此处有子弹 "<<endl;
continue;
}
next.t = f.t+1;
next.x=px;
next.y=py;
vis[px][py][f.t+1]=1;
qu.push(next); //将合格点入栈
}
}
while(!qu.empty())qu.pop();
}
int main()
{
char tmp;
int t,v,x,y;
while(scanf("%d%d%d%d",&m,&n,&k,&maxp)!=EOF)
{
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
{
maze[i][j]=0;
}
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
num[i*mmm+j].clear();
for(int i=0;i<k;i++) //输入城堡的信息
{
getchar();
scanf("%c %d %d %d %d",&tmp,&castle[i].t,&castle[i].v,&castle[i].x,&castle[i].y);
//cout<<tmp<<" "<<castle[i].t<<" "<<castle[i].v<<" "<<castle[i].x<<" "<<castle[i].y<<endl;
maze[castle[i].x][castle[i].y] =-1; //城堡标记为不可达
for(int j=0;j<4;j++)
{
if(tmp ==dirs[j])
{
castle[i].dir =j;break;
}
} //记录该点的方向
}
//预处理
for(int i=0;i<k;i++)
{
//对该点方向上的所有数值 进行更新
int px = castle[i].x;
int py = castle[i].y;
//cout<<"*****"<<px<<" "<<py<<endl;
while(1) //获取新点 进行标记
{
maze[px][py]=i;
px += ddi[castle[i].dir][0];
py += ddi[castle[i].dir][1];
//cout<<px<<" "<<py<<endl;
if(px<0||py<0||px>m||py>n)break;
if(maze[px][py]==-1)break; //如果遇见城堡
// cout<<"可以 "<<px*mmm+py<<endl;
num[px*mmm+py].push_back(i);
}
maze[castle[i].x][castle[i].y] =-1;
}
re=-1;
bfs();
if(re==-1)printf("Bad luck!\n");
else printf("%d\n",re);
}
return 0;
}