HDU 2453 / UVA 4319 - Carrying Out A Task

22 篇文章 0 订阅

 

简述一下题意:

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

 

UVA题目地址: http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2320

 

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;
}


 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值