2018年全国多校算法寒假训练营练习比赛(第四场) - G - 老子的意大利炮呢(搜索)

链接:https://www.nowcoder.com/acm/contest/76/G
来源:牛客网

题目描述 
自攻打过太原县城以后,李云龙这意大利炮就使用的越发的顺手了,指哪打哪也是绝不含糊,于是小野队长开始疯狂打击独立团炮兵营,为了锻炼士兵移动意大利炮的能力,李团长开始给炮兵营进行特训,众(wo)所(xia)周(bian)知(de),意大利炮可由炮管,车轮,炮弹三部分组成,现在李团长在洋村设立阵地,分别把炮管,车轮,炮弹放在三个不同的地方,每一部分的重量不同,所以运输的速度也不相同。团长说:你谁有能耐最快把这意大利炮组装好然后运到我面前,老子就赏他半斤地瓜烧,和尚听了乐坏了,但是他不知道怎么才能使时间最快,你能帮帮他么?
零件只要拿起,就不能放下,所以说不存在在a点拿起,b点放下再去取别的零件一说。默认和尚1秒走一个单位距离,并且只能向上下左右四个方向走,假设和尚现在拿着炮管,那么他每走一单位距离则需要(t1 + 1)秒,如果再拿上车轮,那么他现在每走一步则需要(t1 + t2+1)秒的时间,以此类推。点可以重复经过,路过有零件的点时,可以选择拿或者不拿。
输入描述:
第一行给定两个整数n, m代表地图大小,(1<=n, m <= 100);接下来n行每行有m个由‘#’和‘.’组成的字符,’#’代表墙,’.’代表路,和尚功夫高,可以自己或者带着零件翻墙(不论墙多厚),但是组装好意大利炮之后就必需得走路了。地图画好之后,接下来一行有10个整数sx,sy,x1, y1, x2, y2, x3, y3, ex, ed(都小于100)代表五个点,分别是起始点,炮管的位置,车轮的位置,炮弹的位置,李团长的位置(终点), 五个点保证不同。最后一行三个整数t1, t2, t3,(都大于等于1,小于100),分别代表炮管,车轮,炮弹每走一单位距离需要的时间。题目保证数据合法。
输出描述:
输出一个整数并换行,代表和尚完成任务所需要的最短时间。题目保证有解。
示例1
输入

3 5
##.##
.#.#.
##.##
1 3 2 1 2 3 2 5 3 3 
1 5 4
输出

34
说明

对于第一组样例,我们发现只有在2号零件也就是车轮的位置组装完才能运回到李团长的位置,所以最优解为:起始点->1号零件 –> 3号零件-> 2号零件->李团长
路线为(1,3),(2,3),(2,2),(2,1),(2,2),(2,3),(2,4),(2,5),(2,4),(2,3),(3,3)。
答案为34。


还没凑齐三个零件时可以无视墙壁,距离就是 abs(x1-x2) + abs(y1-y2)

有六种选择方案,就是123的全排列:123,132,213,231,312,321

六种中取最小,还要注意集齐后不可翻墙,所以要判断能否到达终点


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int N = 1e2 + 10;
int n, m;
char mp[N][N];
int x[5],y[5],d[5][5],t[5],vis[N][N];
int dir[4][2]={0,1,1,0,0,-1,-1,0};
int a[10][5] = {{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}};
struct node{
    int x,y;
    node(){}
    node(int a,int b){x = a; y = b;}
};
void bfs(int sx,int sy){
    memset(vis,0,sizeof vis);
    queue<node>q; q.push(node(sx,sy)); vis[sx][sy] = 1;
    while(!q.empty()){
        int x = q.front().x, y = q.front().y; q.pop();
        for(int i=0;i<4;i++){
            int X = x + dir[i][0], Y = y + dir[i][1];
            if(X<=0||X>n||Y<=0||Y>m||vis[X][Y]||mp[X][Y]=='#') continue;
            vis[X][Y] = vis[x][y]+1;
            q.push(node(X, Y));
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    for(int i=0;i<5;i++) scanf("%d%d",&x[i],&y[i]);
    for(int i=1;i<=3;i++) scanf("%d",&t[i]);
    for(int i=0;i<4;i++) for(int j=0;j<4;j++) d[i][j] = abs(x[i]-x[j]) + abs(y[i]-y[j]);
    bfs(x[4],y[4]); for(int i=1;i<=3;i++) d[i][4] = vis[x[i]][y[i]] - 1;
    int ans = 1e9;
    for(int i=0;i<6;i++)
        if(d[a[i][2]][4]!=-1)
            ans = min(ans, d[0][a[i][0]] + d[a[i][0]][a[i][1]] * (1+t[a[i][0]]) + d[a[i][1]][a[i][2]] * (1+t[a[i][0]]+t[a[i][1]]) + d[a[i][2]][4] * (1+t[a[i][0]]+t[a[i][1]]+t[a[i][2]]));
    printf("%d\n", ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值