https://ac.nowcoder.com/acm/contest/318/H
C++版本一
题解:直接bfs,对每个状态记录一下他收集了那些快乐水。记录状态有一个小技巧,二进制压缩记录状态。(自己百度状压去)用3位二进制数记录你获得了那些快乐水。栗子:000表示你有0瓶快乐水,001表示你有第一瓶快乐水,110表示你有第二,三瓶快乐水,依次类推。一共有8个状态0-7,用vis[state][x][y]表示你从起点到达(x,y)位置且状态为sta的最小消耗。注意,当你经过快乐水的节点你可以选择捡起或不捡起来。
Ps:细节见代码,当然自己补题更好。
#include<bits/stdc++.h>
#define mme(a,b) memset((a),(b),sizeof((a)))
#define ***(x) cout<<"* "<<x<<"\n"
using namespace std;
typedef long long LL;
const int N = 1e2 + 7;
const int INF = 0x3f3f3f3f;
struct lp {
int x, y, num, step;
} AA, BB;
int n, m, ans;
char ar[N][N];
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
int vis[N][N][8];
int sx, sy, ex, ey;
int kx[4], ky[4], cost[4];
inline int get_num(int x, int y) {
for(int i = 1; i <= 3; ++i) if(x == kx[i] && y == ky[i]) return i;
return -1;
}
inline int get_cost(int num) {
int ans = 0;
for(int i = 0; i < 3; ++i) if(num & (1 << i))ans = max(ans, cost[i + 1]);
return ans;
}
void bfs() {
for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) for(int k = 0; k <= 7; ++k)
vis[i][j][k] = INF;
queue<lp> Q;
AA.x = sx, AA.y = sy, AA.num = 0;
AA.step = 0;
Q.push(AA);
vis[sx][sy][0] = 0;
while(!Q.empty()) {
AA = Q.front(); Q.pop();
if(AA.x == ex && AA.y == ey && AA.num == 7) {
ans = min(AA.step, ans);
continue;
}
int cc = get_cost(AA.num);
//printf("x = %d y = %d step = %d num = %d\n\n", AA.x, AA.y, AA.step, AA.num);
for(int i = 0; i < 4; ++i) {
int px = AA.x + dir[i][0];
int py = AA.y + dir[i][1];
if(px <= 0 || py <= 0 || px > n || py > m) continue;
if(ar[px][py] == '#' && AA.num == 7) continue;
BB.step = AA.step + cc + 1;
if(BB.step >= vis[px][py][AA.num]) continue;
BB.x = px, BB.y = py;
BB.num = AA.num;
vis[px][py][BB.num] = BB.step;
Q.push(BB);
int key_num = get_num(px, py);
if(key_num != -1 && ((BB.num&(1<<(key_num-1))) == 0)) {
BB.num |= (1 << (key_num-1));
if(BB.step >= vis[px][py][BB.num]) continue;
vis[px][py][BB.num] = BB.step;
Q.push(BB);
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("E://A//shuju//5.in", "r", stdin);
freopen("E://A//shuju//5.out", "w", stdout);
#endif
int tim;
scanf("%d", &tim);
while(tim --) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%s", ar[i] + 1);
for(int j = 1; j <= m; ++j) {
if(ar[i][j] == 'S') sx = i, sy = j;
if(ar[i][j] == 'E') ex = i, ey = j;
if(ar[i][j] == 'X') kx[1] = i, ky[1] = j;
if(ar[i][j] == 'Y') kx[2] = i, ky[2] = j;
if(ar[i][j] == 'Z') kx[3] = i, ky[3] = j;
}
}
for(int i = 1; i <= 3; ++i) scanf("%d", &cost[i]);
ans = INF;
bfs();
printf("%d\n", ans);
}
return 0;
}
C++版本二
题解:注意到题目说的当你没有集齐所有快乐水的每次移动花费为1.所以你可以预处理出S,X,Y,Z四点之间的曼哈顿距离。然后终点以满的花费跑一次有障碍物的普通bfs,记录到X,Y,Z的最小体力花费。然后枚举一遍X,Y,Z的收集顺序,选取最优解即可。此方法效率更高。
#include <bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define ***(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int T, n, m, sx, sy, lx, ly, ax, bx, cx, ay, by, cy, a, b, c;
char mp[105][105];
int dis[105][105];
bool vis[105][105];
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
int p[5] = {1, 2, 3};
struct Node {
int x, y, val;
} e[5];
struct node {
int x, y, stp;
node() {}
node(int x, int y, int stp): x(x), y(y), stp(stp) {}
};
bool ok(int x, int y) {
if (x < 1 || y < 1 || x > n || y > m) return 0;
else return 1;
}
void bfs(int cost) {
CLR(vis, 0);
CLR(dis, 0x3f);
dis[lx][ly] = 0;
vis[lx][ly] = 1;
queue<node> que;
que.push(node(lx, ly, 0));
while (!que.empty()) {
node tmp = que.front(); que.pop();
dis[tmp.x][tmp.y] = tmp.stp;
for (int i = 0; i < 4; i++) {
int dx = tmp.x + dir[i][0];
int dy = tmp.y + dir[i][1];
if (!ok(dx, dy)) continue;
if (mp[dx][dy] == '#' || vis[dx][dy]) continue;
vis[dx][dy] = 1;
que.push(node(dx, dy, tmp.stp + cost));
}
}
}
int calc(int x1, int y1, int x2, int y2) {
return abs(x1 - x2) + abs(y1 - y2);
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
int tmp = 0;
for (int i = 1, x; i <= 3; i++) scanf("%d", &e[i].val), tmp = max(tmp, e[i].val);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (mp[i][j] == 'S') {
sx = i;
sy = j;
}else if (mp[i][j] == 'E') {
lx = i;
ly = j;
}else if (mp[i][j] == 'X') {
e[1].x = i;
e[1].y = j;
}else if (mp[i][j] == 'Y') {
e[2].x = i;
e[2].y = j;
}else if (mp[i][j] == 'Z') {
e[3].x = i;
e[3].y = j;
}
}
}
bfs(tmp+1);
int min_ans = INF;
for(int i = 1; i <= 3; ++i) p[i] = i;
do {
/*for(int i = 1; i <= 3; ++i) printf("%d ", p[i]);
printf("\n");*/
int sum = dis[e[p[3]].x][e[p[3]].y];
sum += calc(sx, sy, e[p[1]].x, e[p[1]].y);
tmp = 0;
for(int i = 1; i <= 2; ++i) {
tmp = max(tmp, e[p[i]].val);
sum += (tmp+1)*calc(e[p[i]].x, e[p[i]].y, e[p[i + 1]].x, e[p[i + 1]].y);
}
min_ans = min(min_ans, sum);
} while (next_permutation(p + 1, p + 4));
printf("%d\n", min_ans);
}
return 0;
}
C++版本三
#include "bits/stdc++.h"
using namespace std;
const int dir[4][2] = {-1,0,0,-1,0,1,1,0};
int N, M, sx, sy, ans, a[5];
bool che(int x, int y)
{
return x>=1 && y>=1 && x<=N && y<=M;
}
char mp[105][105];
bool vis[105][105][10];
struct node
{
int x ,y, state, speed, t;
node(int a=0, int b=0, int c=0, int d=0, int tt=0):x(a), y(b), state(c), speed(d), t(tt) {}
friend bool operator < (node e1, node e2) { return e1.t > e2.t; }
};
void bfs()
{
memset(vis, false, sizeof(vis));
priority_queue<node> Q;
Q.push(node(sx,sy,0,0,0));
vis[sx][sy][0] = true;
while(!Q.empty())
{
node tmp = Q.top(); Q.pop();
for(int i=0; i<4; i++)
{
int xx = tmp.x + dir[i][0], yy = tmp.y + dir[i][1];
if(!che(xx, yy) || (tmp.state == 7 && mp[xx][yy] == '#')) continue;
if(mp[xx][yy] == 'E')
{
if(tmp.state == 7) { ans = tmp.t + tmp.speed + 1; return; }
if(vis[xx][yy][tmp.state]) continue;
vis[xx][yy][tmp.state] = true;
Q.push(node(xx, yy, tmp.state, tmp.speed, tmp.t + tmp.speed + 1));
}
else if(mp[xx][yy]>='X' && mp[xx][yy]<='Z')
{
int id = (mp[xx][yy] - 'X');
if( (tmp.state>>id) & 1)
{
if(vis[xx][yy][tmp.state]) continue;
vis[xx][yy][tmp.state] = true;
Q.push(node(xx, yy, tmp.state, tmp.speed, tmp.t + tmp.speed + 1));
}
else
{
if(!vis[xx][yy][tmp.state])
{
vis[xx][yy][tmp.state] = true;
Q.push(node(xx, yy, tmp.state, tmp.speed, tmp.t + tmp.speed + 1));
}
int state = (tmp.state | (1<<id)), speed = max(tmp.speed, a[id]);
vis[xx][yy][state] = true;
Q.push(node(xx, yy, state, speed, tmp.t + tmp.speed + 1));
}
}
else
{
if(vis[xx][yy][tmp.state]) continue;
vis[xx][yy][tmp.state] = true;
Q.push(node(xx, yy, tmp.state, tmp.speed, tmp.t + tmp.speed + 1));
}
}
}
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &N, &M);
for(int i=1; i<=N; i++)
{
scanf("%s", mp[i]+1);
for(int j=1; j<=M; j++)
{
if(mp[i][j] == 'S')
{
sx = i;
sy = j;
mp[i][j] = '.';
}
}
}
scanf("%d%d%d", &a[0], &a[1], &a[2]);
//ans = INF;
bfs();
printf("%d\n", ans);
}
return 0;
}