题目链接:http://acm.csust.edu.cn/problem/3021
Description
众所周知,洛克王国的星辰塔镇守着洛克王国的边陲,而这一次,我们的小洛克lonely_wind在域外与宠物们走散了(实际上是被域外魔物冲散的)。
离开了训练师的宠物们就会变成游离状态,是无法自己移动的,lonely_wind想要与宠物们汇合的话,只能自己去寻找宠物们。
lonely_wind每1秒都可以往上下左右的某一个方向移动一格,当宠物们与lonely_wind汇合时,lonely_wind的攻击力会加上宠物们的攻击力。
现在由于域外魔物的存在,lonely_wind不得不小心翼翼。
lonely_wind如今已是王国的圣魔导师了,如果他和他的宠物们的攻击力大于魔物,则他凭借着强大的实力可以击杀魔物,否则会被魔物吞噬,
离开了训练师的宠物们则处于游离状态,所以会被魔物无视(也就是说魔物并不会攻击还没有和lonely_wind汇合的宠物)。
现在已知魔物每2秒会向四周(上下左右四个方向)扩散一格,同时攻击高的魔物会覆盖攻击低的魔物,
若小洛克和魔物同时到达某一个位置,则只有当到达该位置之前的小洛克的战斗力比魔物大时小洛克才可存活。
除此之外,若小洛克将到达一个已被魔物覆盖的宠物,小洛克必须先战胜那只魔物才能获得宠物。
当没有宠物是游离状态的时候,lonely_wind将打开传送之门,请计算他们逃亡的最短时间,若无法集结则输出“you die!”。
Input
第一行三个整数,n,m,atk(n,m代表地图大小,地图外为死亡深渊,入者即死, atk为洛克的攻击力)(4≤n,m≤1000)
接下来n行m列的图,‘.’代表空地,‘*’表示魔物,‘#’表示宠物,‘L’为洛克。
接下来一行为魔物的攻击力,以最左上方的魔物为第一个,最右下角的魔物为最后一个,以从左到右,从上到下的顺序给出。
再接下来一行为宠物的攻击力,给出顺序与魔物相同。
其中宠物的数量≤2, 魔物的数量≤20,所有攻击值数据在int范围内。
Output
逃亡的最短时间,如果无法汇合,输出“you die!”。
Sample Input 1
4 4 3 ..#. .L.* .... .#*. 2 3 1 7
Sample Output 1
6
Sample Input 2
4 4 4 ...# .L.. ..*. *..# 2 4 1 5
Sample Output 2
6
Hint
样例1:
第一个魔物的坐标为(2,4),攻击力为2,第二个魔物的坐标为(4,3),攻击力为3。
第一个宠物的坐标为(1,3),攻击力为1,第二个宠物坐标为(4,2),攻击力为7。
lonely_wind先向上走一格,再向右走一格,拿到第一个宠物,此时他的攻击力增加为4,所以两个魔物都会被lonely_wind给击败。
接下来再向下走3格,向右走1格,拿到第二个宠物,就可以打开传送门了。
lonely_wind总共走了6格,所以答案为6。
实际上这题也是很简单,只不过代码量比纯签到题多了一点所以才放到了中等题中...
让我伤心的是,这题连提交的人都没有。。。其他题目好歹有提交,虽然WA了不少。。。QAQ
我们可以先只考虑暴力,也就是先20遍bfs遍历所有的魔物,然后在地图上记录一下每个魔物抵达的时间和该时间点的最大攻击。
接下来由于最多只有两个宠物,我们跑4次bfs就好了,洛克到1号宠物再到2号,洛克到2号再到1号。于是这题就愉快的暴力掉了4000ms+。然后就是考虑优化了。
其实也不需要优化太多,我们可以将所有魔物全部放进队列中一起跑,然后稍微剪个枝就可以过了。我们知道如果一个魔物后抵达A,而它的攻击又弱于或者等于前一个抵达的魔物,那么我们就可以将这个状态给舍弃掉了。1500ms
然后。。。本来是时限2S 的,不过牛客上2s的标程要跑太久了。。。所以PC改成1s了。。。。nmd我就估摸着没人过了。。。
以下是1500ms的现场赛AC代码:
#include <bits/stdc++.h> using namespace std; #define ok(x,y,n,m) (x>=1 && x<=n && y>=1 && y<=m) const int inf=1e9; char a[1002][1002]; int dx[]={-1,1,0,0},dy[]={0,0,1,-1}; int lim=inf,visxl[10]; bool vis[1002][1002][22]; struct node { int x,y,atk,p; }evil[25],god[10]; struct node2 { int x,y,atk,p,t; }; struct Map { int t,atk; }ev[1002][1002][22]; void bfs(int pp,int use,int n,int m) { queue<node2>q; int t=0; for (int i=1; i<=pp; i++){ int x,y,atk; x=evil[i].x;y=evil[i].y;atk=evil[i].atk; q.push(node2{x,y,atk,evil[i].p,t}); ev[x][y][i]=Map{0,atk}; } while (!q.empty()){ node2 s=q.front(); q.pop(); int x=s.x,y=s.y,p=s.p,atk=s.atk; if (vis[x][y][p]) continue; vis[x][y][p]=true; for (int i=0; i<4; i++){ int xx=x+dx[i],yy=y+dy[i]; t=s.t+2; if (!ok(xx,yy,n,m)) continue; if (vis[xx][yy][p]) continue; int j; for (j=1; j<=pp; j++){ if (ev[xx][yy][j].atk>=atk && ev[xx][yy][j].t<=t) break; } if (j<=pp) continue; node2 ss=s; ss.t=t;ss.x=xx;ss.y=yy; ev[xx][yy][p]=Map{t,atk}; q.push(ss); } } } struct hhh { int t,atk; }; bool vL[1002][1002]; hhh bfsL(int sx,int sy,int v,int fx,int fy,int n,int m,int satk,int p,int bast) { if (sx==fx && sy==fy) return {0,satk}; queue<node2>q; node2 s; s.x=sx;s.y=sy;s.atk=satk;s.t=bast; q.push(s); memset(vL,false,sizeof(vL)); while (!q.empty()){ s=q.front(); q.pop(); int x=s.x,y=s.y; if (vL[x][y]) continue; vL[x][y]=true; for (int i=0; i<4; i++){ int xx=x+dx[i],yy=y+dy[i]; if (vL[xx][yy]) continue; if (!ok(xx,yy,n,m)) continue; int j; for (j=1; j<=p; j++){ if (ev[xx][yy][j].t<=s.t+1 && s.atk<=ev[xx][yy][j].atk) break; } if (j<=p) continue; if (xx==fx && yy==fy) return {s.t+1,s.atk+god[v].atk}; node2 ios=s; ios.x=xx;ios.y=yy;ios.t+=1; q.push(ios); } } return {inf,0}; } int main() { int n,m,satk; scanf ("%d%d%d",&n,&m,&satk); for (int i=1; i<=n; i++) scanf ("%s",a[i]+1); int p=0,use=0,sx,sy; for (int i=1; i<=n; i++) for (int j=1; j<=m; j++){ if (a[i][j]=='*') evil[++p]=node{i,j,0,p}; else if (a[i][j]=='#') god[++use]=node{i,j,0,use}; else if (a[i][j]=='L') sx=i,sy=j; } for (int i=1; i<=p; i++) { int x;scanf ("%d",&x); evil[i].atk=x; } for (int i=1; i<=use; i++){ int x;scanf ("%d",&x); god[i].atk=x; } if (!use) { printf ("0 ");return 0; } god[0].x=sx,god[0].y=sy; bfs(p,use,n,m); hhh s1,s2,s3,s4; s1=s2=s3=s4={inf,0}; if (use){ if (use>=1){ s1=bfsL(sx,sy,1,god[1].x,god[1].y,n,m,satk,p,0); } if (use>1) { s2=bfsL(god[1].x,god[1].y,2,god[2].x,god[2].y,n,m,s1.atk,p,s1.t); s3=bfsL(sx,sy,2,god[2].x,god[2].y,n,m,satk,p,0); s4=bfsL(god[2].x,god[2].y,1,god[1].x,god[1].y,n,m,s3.atk,p,s3.t); } } int ans1,ans2; if (use>1){ lim=min(s2.t,s4.t); } else lim=s1.t; if (lim>=inf) printf ("you die! "); else printf ("%d ",lim); return 0; }
当然其实还可以再优化的,考虑到没有障碍物的情况,我们可以利用曼哈顿距离做一下操作,我们可以两个队列同时跑,这样我们的宠物能否到达判断就不需要对每个魔物的到达时间和攻击判断,只需要对比一下最大ATK就好了,魔物的队列和之前一样的优化一下就好了,宠物的话利用曼哈顿距离搞搞和之前的写法差别不大。
这里给一手嫖老板的500msAC代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e3 + 50; int INF = 1e8; char mp[maxn][maxn]; int n, m; struct st { int x, y, atk; int t, num; } am[maxn], ac[maxn]; int cntm, cntc; int sx, sy; int id[maxn][maxn]; int dis[5][maxn][maxn]; int matk[maxn][maxn]; int tx[] = {0, -1, 0, 1}; int ty[] = {1, 0, -1, 0}; queue<st> quec, quem; int ans = INF; int res = 0; void bfs(int atk){ quec.push({sx, sy, atk, 1, 0}); for(int i = 1; i <= cntm; i++){ quem.push(am[i]); } for(int i = 0; i <= 2; i++){ for(int j = 1; j <= n; j++){ for(int k = 1; k <= m; k++){ dis[i][j][k] = INF; } } } dis[0][sx][sy] = 0; for(int t = 1; ; t++){ int flag = 0; while(quem.size() && quem.front().t == t){ st tmp = quem.front(); quem.pop(); int x = tmp.x, y = tmp.y; for(int i = 0; i < 4; i++){ int nx = x + tx[i], ny = y + ty[i]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && tmp.atk > matk[nx][ny]){ matk[nx][ny] = tmp.atk; quem.push({nx, ny, tmp.atk, t + 2, 0}); } } } while(quec.size() && quec.front().t == t){ flag = 1; st tmp = quec.front(); quec.pop(); int x = tmp.x, y = tmp.y; for(int i = 0; i < 4; i++){ int nx = x + tx[i], ny = y + ty[i]; if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && tmp.atk > matk[nx][ny] && dis[tmp.num][nx][ny] > dis[tmp.num][x][y] + 1){ dis[tmp.num][nx][ny] = dis[tmp.num][x][y] + 1; int num = tmp.num; atk = tmp.atk; if(id[nx][ny]){ num ^= (1 << (id[nx][ny] - 1)); atk += ac[id[nx][ny]].atk; } dis[num][nx][ny] = dis[tmp.num][x][y] + 1; if(num == res) ans = min(ans, dis[num][nx][ny]); quec.push({nx, ny, atk, t + 1, num}); } } } if(flag == 0) break; } } int main() { int atk; scanf("%d%d%d", &n, &m, &atk); for(int i = 1; i <= n; i++){ scanf("%s", mp[i] + 1); } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(mp[i][j] == 'L'){ sx = i, sy = j; } if(mp[i][j] == '#'){ ac[++cntc] = {i, j, 0, 1, 0}; id[i][j] = cntc; res ^= (1 << (cntc - 1)); } if(mp[i][j] == '*'){ am[++cntm] = {i, j, 0, 2, 0}; } } } for(int i = 1; i <= cntm; i++){ scanf("%d", &am[i].atk); matk[am[i].x][am[i].y] = am[i].atk; } for(int i = 1; i <= cntc; i++){ scanf("%d", &ac[i].atk); } if(cntc == 0){ printf("0 "); } else { bfs(atk); if(ans == INF){ printf("you die! "); } else { printf("%d ", ans); } } return 0; }