复习2019年9月4日
注意剪枝的条件 还有最后判断flag
总时间限制:
1000ms
内存限制:
65536kB
描述
佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?
已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?
输入
输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。
输出
输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。
样例输入
样例输入1
4 4 1
#@##
**##
###+
****
样例输入2
4 4 2
#@##
**##
###+
****
样例输出
样例输出1
6
样例输出2
4
内心os:这中二的题目@_@
理解题意:就是一个有附加条件的迷宫最短路。
一开始想要用BFS 然后发现好像是最短路,还有附加条件于是就开始写dfs,然鹅TLE
TLE的代码
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f
const int maxn=250;
int m,n,t;
int sx,sy,ex,ey,ans; //起点 终点的坐标
bool f;
int go[][2]={1,0,
-1,0,
0,1,
0,-1};
int visit[maxn][maxn];
char G[maxn][maxn];
/*struct Node{
int x,y,time,a;
Node() {}
Node(int xx,int yy,int tt,int aa):x(xx),y(yy),time(tt),a(aa){}
};
queue Q;*/
void init(){
memset(visit,0,sizeof(visit));
ans=INF;
f= false;
}
void read(){
cin>>m>>n>>t;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cin>>G[i][j];
if(G[i][j]=='@'){
sx=i;
sy=j;
}
if(G[i][j]=='+'){
ex=i;
ey=j;
}
}
}
}
bool inside(int x,int y){
return x>=1 && x<=m && y>=1 && y<=n;
}
void DFS(int x,int y,int time,int a){
if(x==ex && y==ey){
f=true;
if(ans>time)
ans=time;
return;
}
for(int i=0;i<4;i++){
int xx=x+go[i][0];
int yy=y+go[i][1];
int tt=time+1;
if(inside(xx,yy) && !visit[xx][yy] && tt=1){
visit[xx][yy]=1;
DFS(xx,yy,time+1,a-1);
visit[xx][yy]=0;
}
else if(G[xx][yy]=='*' || G[xx][yy]=='+'){ //一开始忘记加+的条件
visit[xx][yy]=1;
DFS(xx,yy,time+1,a);
visit[xx][yy]=0;
}
}
}
}
int main(){
init();
read();
DFS(sx,sy,0,t);
if(f) cout<
参考方法:https://zhuanlan.zhihu.com/p/61355033
剪枝 方法 ==>增加状态记录 在位置(x,y)时候金币数a时候的步数 ,如果再次碰到相同情况且步数> = 则直接return
“到当前位置消耗一定的查克拉时,所走的步数不能比以前走的多 ” (肯定是绕路了)
AC代码:
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f
const int maxn=250;
int m,n,t;
int sx,sy,ex,ey,ans; //起点 终点的坐标
bool f;
int go[][2]={1,0,
-1,0,
0,1,
0,-1};
int visit[maxn][maxn];
int step[maxn][maxn][maxn];
char G[maxn][maxn];
/*struct Node{
int x,y,time,a;
Node() {}
Node(int xx,int yy,int tt,int aa):x(xx),y(yy),time(tt),a(aa){}
};
queue Q;*/
void init(){
memset(visit,0,sizeof(visit));
ans=INF;
memset(step,0x3f,sizeof(step));
f= false;
}
void read(){
cin>>m>>n>>t;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cin>>G[i][j];
if(G[i][j]=='@'){
sx=i;
sy=j;
}
if(G[i][j]=='+'){
ex=i;
ey=j;
}
}
}
}
bool inside(int x,int y){
return x>=1 && x<=m && y>=1 && y<=n;
}
void DFS(int x,int y,int time,int a){
if(time>=step[x][y][a]) return;
//走到当前位置消耗一定的查克拉时,所走的步数不能比以前走的多
if(x==ex && y==ey){
f=true;
if(ans>time)
ans=time;
return;
}
step[x][y][a]=time;
for(int i=0;i<4;i++){
int xx=x+go[i][0];
int yy=y+go[i][1];
int tt=time+1;
if(inside(xx,yy) && !visit[xx][yy] && tt=1){
visit[xx][yy]=1;
DFS(xx,yy,time+1,a-1);
visit[xx][yy]=0;
}
else if(G[xx][yy]=='*' || G[xx][yy]=='+' && tt
解题方法:BFS 之所以一开始没写成是因为不知道怎么处理visit
发现别的blog的思路 用visit数组储存
参考链接:https://blog.csdn.net/curson_/article/details/52062695
这个写的很清晰,那个金币数(也就是查克拉)的理解好像还不太理解QAQ
AC代码
一开始visit一定要初始化为 -1 ,要不然后面比较金币数
是当前金币数 > 之前走过下一位置的金币数
我分类讨论了一下,貌似不讨论也可
用visit[x][y]表示经过点(x,y)后的金币数,如果下一个是要消耗金币那么就。。;
如果不需要消耗金币就。。。
代码里有
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f
const int maxn=250;
int m,n,v;
int sx,sy,ex,ey,ans; //起点 终点的坐标
bool f;
int go[][2]={1,0,
-1,0,
0,1,
0,-1};
int visit[maxn][maxn]; //记录上一次走过时的金币
char G[maxn][maxn];
struct Node{
int x,y,time,a;
Node() {}
Node(int xx,int yy,int tt,int aa):x(xx),y(yy),time(tt),a(aa){}
};
queue Q;
void init(){
memset(visit,-1,sizeof(visit));
while(!Q.empty()) Q.pop();
ans=INF;
f=false;
}
void read(){
cin>>m>>n>>v;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cin>>G[i][j];
if(G[i][j]=='@'){
//visit[i][j]=t;
Q.push(Node(i,j,0,v));
}
else if(G[i][j]=='+'){
ex=i;
ey=j;
}
}
}
}
bool inside(int x,int y){
return x>=1 && x<=m && y>=1 && y<=n;
}
void BFS(){
while(!Q.empty()){
Node cur=Q.front();
Q.pop();
int x1=cur.x;
int y1=cur.y;
int time1=cur.time;
int a1=cur.a;
if(x1==ex && y1==ey){
f=true;
if(ans>time1) ans=time1;
}
for(int i=0;i<4;i++){
int xx=x1+go[i][0];
int yy=y1+go[i][1];
if( inside(xx,yy)){ //现在拥有的金币 > 下一个要走的上一次走过时候的金币
if(G[xx][yy]=='#' && a1>=1 && visit[xx][yy]