简述一下题意:
20*20的地图上,一个起点S,一个终点E,障碍物#,漩涡*
一艘船从起点出发,携带充足的A类油和X升B类油。
沿上下左右四个方向行驶,不能在障碍物的格子行驶;可以进入漩涡,但每次进入船会受伤。没走过一个格子都要消耗一升A类油。
每个回合有两个操作:
1.普通航行一格
2.加速一次消耗Y升B类油,有两种加速方法,加速规则:
a.在某一个方向连续航行d步,d步之内不能有障碍物、漩涡,不能驶出地图
b.当下一步要驶入漩涡时,必须加速、进入漩涡后加速效果消失
询问船是否可以到达终点,输出最少多少个回合到达,前提——船受到的伤害最小(进入漩涡次数最少),其次消耗A类油最少(走过的格子数最少),再次回合数最少。
------------------------------题意摘自: http://hi.baidu.com/alpc62/blog/item/ceb5128216a4f7a50cf4d2f8.html---------------------------------
HDU题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=2453
2008年哈尔滨赛区的的题目。
简述方法:限制条件的SPFA。用优先队列,不断更新符合要求的最短路径。
利用num[横坐标][纵坐标][受伤次数] 来记录所剩余的最大加速次数,如果后来者所存有的加速次数比先到者的多,就再走一遍。
利用优先队列,按照 1. 受伤次数最少 、 2. 耗A量最少 、3. 步数最少 ,按顺序进行优先级排序,依次最少的先出队列
这里有两个比较好的剪枝:
1. 先搜索一遍,能否到达终点
2. num[x][y][当前受伤次数-1]的位置如果已经走过,就不再走,既然少受伤一次能都路过,现在就不必再走了
====================================================================================================
WA了几天
现在已经AC了~~
灰常感谢 helaoxuan 大牛, 问的几个人中,只有他回复了邮件!!! 解答了我的疑惑!!!!
错的原因很简单,题意理解搓了, 我将B类油与A类油的消耗分开,也就是说在消耗B油加速时,所走的路不消耗A类油
按照我的理解, 下面注释的数据中,case1的答案应该是5,case2的答案应该是6,case4的答案应该是6.
但其实,真正的题意是,每走一个格子,不管是否加速状态,都需要消耗一个A的油量~~
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=22;
const int fy[]={0,0,-1,1};
const int fx[]={1,-1,0,0};
struct Point{ // damage ,B-cost,A-cost
int x,y,step,dmg,bcst,acst;
Point(){}
Point(int tx,int ty,int ts,int td,int ta,int tb){
x=tx,y=ty,step=ts,dmg=td,acst=ta,bcst=tb;
}
bool friend operator<(Point p,Point q){
if(p.dmg!=q.dmg) return p.dmg>q.dmg;
if(p.acst!=q.acst) return p.acst>q.acst;
return p.step>q.step;
}
};
struct Cdnt{ // Coordinate
int x,y,cst;
Cdnt(){};
Cdnt(int tx,int ty,int tc){x=tx,y=ty,cst=tc;}
bool friend operator<(Cdnt p,Cdnt q){
return p.cst>q.cst;
}
};
char mp[maxn][maxn];
int n,m,sx,sy,dis;
int CBA(){ // E can be arrived ? Return the number of damage.
int k;
bool vis[maxn][maxn];
Cdnt now,next;
priority_queue<Cdnt>q;
memset(vis,false,sizeof(vis));
q.push(Cdnt(sx,sy,0));
vis[sx][sy]=true;
while(!q.empty()){
now=q.top();
q.pop();
if(mp[now.x][now.y]=='E') return now.cst;
for(k=0;k<4;k++){
next.x=now.x+fx[k];
next.y=now.y+fy[k];
if(next.x<0 || next.x>=n || next.y<0 || next.y>=m) continue;
if(vis[next.x][next.y] || mp[next.x][next.y]=='#') continue;
if(mp[next.x][next.y]=='*') next.cst=now.cst+1;
else next.cst=now.cst;
vis[next.x][next.y]=true;
q.push(next);
}
}
return -1;
}
priority_queue<Point>que;
short num[maxn][maxn][maxn*maxn]; // [x][y][number of undercurrent] for accelerate
void init_(int res){
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
for(int k=0;k<=res;k++)
num[i][j][k]=-1;
while(!que.empty()) que.pop();
}
int bfs(int v){ // v -> The number of total acceleration.
int res,k,z;
Point now,next;
res=CBA();
if(res==-1 || res>v) return -1;
init_(res+1);
que.push(Point(sx,sy,0,1,0,v));
num[sx][sy][1]=v;
while(!que.empty()){
now=que.top();
que.pop();
// cout<<now.x<<" "<<now.y<<endl;
if(mp[now.x][now.y]=='E') return now.step;
for(k=0;k<4;k++){
if(now.bcst>res-now.dmg){
next=now;
for(z=0;z<dis;z++){
next.x+=fx[k];
next.y+=fy[k];
if(next.x>=n || next.y>=m || next.x<0 || next.y<0) break;
if(mp[next.x][next.y]=='#' || mp[next.x][next.y]=='*') break;
}
if(z==dis){
next.step++;
next.bcst--;
next.acst+=dis;
if(num[next.x][next.y][next.dmg]<next.bcst && num[next.x][next.y][next.dmg-1]==-1){
num[next.x][next.y][next.dmg]=next.bcst;
que.push(next);
}
}
}
next=now;
next.x+=fx[k];
next.y+=fy[k];
next.step++;
next.acst++;
if(next.x>=n || next.y>=m || next.x<0 || next.y<0) continue;
if(mp[next.x][next.y]=='#') continue;
if(mp[next.x][next.y]=='*'){
if(next.bcst>0) next.bcst--,next.dmg++;
else continue;
}
if(num[next.x][next.y][next.dmg]<next.bcst && num[next.x][next.y][next.dmg-1]==-1){
num[next.x][next.y][next.dmg]=next.bcst;
que.push(next);
}
}
}
return -1;
}
int main(){
int t,i,j,res;
scanf("%d",&t);
while(t--){
scanf("%d%d\n",&n,&m);
for(i=0;i<n;i++){
gets(mp[i]);
for(j=0;j<m;j++)
if(mp[i][j]=='S')
sx=i,sy=j;
}
scanf("%d",&dis);
scanf("%d%d",&i,&j);
res=bfs(i/j);
if(res==-1) puts("can not reach!");
else printf("%d\n",res);
}
return 0;
}
/*
Case1:-----------------------------------
1
7 9
#########
# ######
#S #
# ##### #
# # #*#
# *E#
#########
4
4 1
answer1: 6 -----------------------------------
Case2:-----------------------------------
1
8 8
########
#S #
# ### #
## # # #
# E # #
# #### #
# #
########
5
3 1
answer2: 4 -----------------------------------
Case3:-----------------------------------
1
20 20
####################
#S #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# #
# E#
####################
17
2 1
answer3: 2 -----------------------------------
Case4:-----------------------------------
1
20 20
####################
#S #
# ###### #
# # #
# # #
# # #### #
# # #
# # #
# # #
# # ######
# #
# # # #
# # # #
#### ##### ## # #
# # # #
# # # #
# # # #
# ##### ####### #
# E#
####################
9
6 1
answer4: 18 -----------------------------------
*/
其实我还是蛮舍不得以前的代码,所以贴出来一起分享:
如果在消耗B类油的时候,不消耗A类油。也就是说,两种加速:不管是加速进入旋窝,还是往前加速d个单元格,都不耗A类油。
前提还是一样的。 第一前提:伤害最少、第二前提:A耗最少、第三前提:步数最少
那么代码应该如下:
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=22;
const int fy[]={0,0,-1,1};
const int fx[]={1,-1,0,0};
struct Point{ // damage ,B-cost,A-cost
int x,y,step,dmg,bcst,acst;
Point(){}
Point(int tx,int ty,int ts,int td,int ta,int tb){
x=tx,y=ty,step=ts,dmg=td,acst=ta,bcst=tb;
}
bool friend operator<(Point p,Point q){
if(p.dmg!=q.dmg) return p.dmg>q.dmg;
if(p.acst!=q.acst) return p.acst>q.acst;
return p.step>q.step;
}
};
struct Cdnt{ // Coordinate
int x,y,cst;
Cdnt(){};
Cdnt(int tx,int ty,int tc){x=tx,y=ty,cst=tc;}
bool friend operator<(Cdnt p,Cdnt q){
return p.cst>q.cst;
}
};
char mp[maxn][maxn];
int n,m,sx,sy,dis;
int CBA(){ // E can be arrived ? Return the number of damage.
int k;
bool vis[maxn][maxn];
Cdnt now,next;
priority_queue<Cdnt>q;
memset(vis,false,sizeof(vis));
q.push(Cdnt(sx,sy,0));
vis[sx][sy]=true;
while(!q.empty()){
now=q.top();
q.pop();
if(mp[now.x][now.y]=='E') return now.cst;
for(k=0;k<4;k++){
next.x=now.x+fx[k];
next.y=now.y+fy[k];
if(next.x<0 || next.x>=n || next.y<0 || next.y>=m) continue;
if(vis[next.x][next.y] || mp[next.x][next.y]=='#') continue;
if(mp[next.x][next.y]=='*') next.cst=now.cst+1;
else next.cst=now.cst;
vis[next.x][next.y]=true;
q.push(next);
}
}
return -1;
}
priority_queue<Point>que;
short num[maxn][maxn][maxn*maxn]; // [x][y][number of undercurrent] for accelerate
short cost[maxn][maxn][maxn*maxn]; // cost of A
void init_(int res){
int i,j,k;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
for(k=0;k<=res;k++)
cost[i][j][k]=maxn*maxn,num[i][j][k]=-1;
while(!que.empty()) que.pop();
}
int bfs(int v){ // v -> The number of total acceleration.
int res,k,z;
Point now,next;
res=CBA();
if(res==-1 || res>v) return -1;
init_(res+1);
que.push(Point(sx,sy,0,1,0,v));
cost[sx][sy][1]=0;
num[sx][sy][1]=v;
while(!que.empty()){
now=que.top();
que.pop();
// cout<<now.x<<" "<<now.y<<endl;
if(mp[now.x][now.y]=='E') return now.step;
for(k=0;k<4;k++){
if(now.bcst>res-now.dmg){
next=now;
for(z=0;z<dis;z++){
next.x+=fx[k];
next.y+=fy[k];
if(next.x>=n || next.y>=m || next.x<0 || next.y<0) break;
if(mp[next.x][next.y]=='#' || mp[next.x][next.y]=='*') break;
}
if(z==dis){
next.step++;
next.bcst--;
if((cost[next.x][next.y][next.dmg]>next.acst || num[next.x][next.y][next.dmg]<next.bcst)&& num[next.x][next.y][next.dmg-1]==-1){
if(cost[next.x][next.y][next.dmg]>next.acst)
cost[next.x][next.y][next.dmg]=next.acst;
if(num[next.x][next.y][next.dmg]<next.bcst)
num[next.x][next.y][next.dmg]=next.bcst;
que.push(next);
}
}
}
next=now;
next.x+=fx[k];
next.y+=fy[k];
next.step++;
next.acst++;
if(next.x>=n || next.y>=m || next.x<0 || next.y<0) continue;
if(mp[next.x][next.y]=='#') continue;
if(mp[next.x][next.y]=='*'){
if(next.bcst>0) next.bcst--,next.acst--,next.dmg++;
else continue;
}
if((cost[next.x][next.y][next.dmg]>next.acst || num[next.x][next.y][next.dmg]<next.bcst)&& num[next.x][next.y][next.dmg-1]==-1){
if(cost[next.x][next.y][next.dmg]>next.acst)
cost[next.x][next.y][next.dmg]=next.acst;
if(num[next.x][next.y][next.dmg]<next.bcst)
num[next.x][next.y][next.dmg]=next.bcst;
que.push(next);
}
}
}
return -1;
}
int main(){
int t,i,j,res;
scanf("%d",&t);
while(t--){
scanf("%d%d\n",&n,&m);
for(i=0;i<n;i++){
gets(mp[i]);
for(j=0;j<m;j++)
if(mp[i][j]=='S')
sx=i,sy=j;
}
scanf("%d",&dis);
scanf("%d%d",&i,&j);
res=bfs(i/j);
if(res==-1) puts("can not reach!");
else printf("%d\n",res);
}
return 0;
}