题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1044
题目大意:
在一个迷宫中,从起点走到终点,还有几个宝物,问在给定的时间内,到达终点后所能获取的最大价值。
1.状态压缩记录状态,用十位的二进制数表示每个宝石选还是不选,共有2^10=1024个状态,开个数组vis[maxn][maxn][1024]判断在每一点是否达到该状态,bfs搜索最短路径,W*H*1024个状态都要搜到,复杂度较高
#include <stdio.h> #include <queue> #include <memory.h> using namespace std; int W, H, L, M; bool vis[55][55][1100]; char g[55][55]; int money[15]; int dx[] = { -1, 1, 0, 0 }; int dy[] = { 0, 0, -1, 1 }; struct node { int x, y, state, val, time; }; bool check(int x, int y){ if (x<0 || x>H - 1 || y<0 || y>W - 1)return false; if (g[x][y] == '*')return false; return true; } int bfs(int sx, int sy) { memset(vis, 0, sizeof(vis)); queue<node>q; node cur, next; cur.x = sx; cur.y = sy; cur.state = 0; cur.time = 0; cur.val = 0; q.push(cur); vis[sx][sy][0] = 1; int ans = -1; while (!q.empty()){ cur = q.front(); q.pop(); for (int i = 0; i < 4; ++i){ next.x = cur.x + dx[i]; next.y = cur.y + dy[i]; if (check(next.x, next.y)){ if (g[next.x][next.y] >= 'A'&&g[next.x][next.y] <= 'J'){ int tmp = g[next.x][next.y] - 'A'; if (!(cur.state&(1<<tmp))){//这一句WA到死,不仅要判断状态是否到达过,而且每个宝石只能拿一次啊,101和100不是同一个状态,但拿了同一个宝石 next.state = cur.state | (1 << tmp); next.val = cur.val + money[tmp]; } } else{ next.state = cur.state; next.val = cur.val; } if (!vis[next.x][next.y][next.state]){ next.time = cur.time + 1; vis[next.x][next.y][next.state] = 1; if (g[next.x][next.y] == '<'){ ans = max(ans, next.val); } if (next.time == L)continue; q.push(next); } } } } return ans; } int main() { //freopen("in.txt", "r", stdin); int T, sx, sy; scanf("%d", &T); for (int _case = 1; _case <= T; ++_case){ scanf("%d %d %d %d", &W, &H, &L, &M); for (int i = 0; i < M; ++i)scanf("%d", &money[i]); for (int i = 0; i < H; ++i) { scanf("%s", g[i]); for (int j = 0; j < W; ++j) { if (g[i][j] == '@') { sx = i; sy = j; g[i][j] == '.'; } } } printf("Case %d:\n", _case); int ans = bfs(sx, sy); if (ans >= 0)printf("The best score is %d.\n", ans); else printf("Impossible\n"); if (_case < T)printf("\n"); } return 0; }
2.bfs+dfs
bfs找到出口到每个宝石,每个宝石之间和所有宝石到出口的路径,只用搜索每个x,y是否已经到达过,复杂度大大降低
dfs找到在time limit内是否能找到出口,记录能拿到的宝石的最大值
注意dfs的剪枝,如果此时拿到宝石的数量已经达到总量,可以不用继续搜索下去了
#include<stdio.h> #include<memory.h> #include<queue> using namespace std; char g[55][55]; int dis[30][30]; int j[15]; int tot; bool vis1[55][55]; bool vis2[30]; int step[55][55]; int t, w, h, L, m; int dx[] = { -1, 1, 0, 0 }; int dy[] = { 0, 0, -1, 1 }; bool check(int x, int y) { if (vis1[x][y])return false; if (x < 0 || x>h - 1 || y<0 || y>w - 1)return false; if (g[x][y] == '*')return false; return true; } void bfs(int x, int y, int tag) { memset(vis1, 0, sizeof(vis1)); memset(step, 0, sizeof(step)); queue<int>q; q.push(x*w + y); vis1[x][y] = 1; step[x][y] = 0; while (!q.empty()){ int cur = q.front(); q.pop(); int x = cur / w; int y = cur%w; for (int i = 0; i < 4; ++i){ int nx = x + dx[i]; int ny = y + dy[i]; if (check(nx, ny)){ vis1[nx][ny] = 1; step[nx][ny] = step[x][y] + 1; if (g[nx][ny] == '@')dis[tag][0] = step[nx][ny]; else if (g[nx][ny] == '<')dis[tag][m + 1] = step[nx][ny]; else if ('A' <= g[nx][ny] && g[nx][ny] <= 'J') dis[tag][g[nx][ny] - 'A' + 1] = step[nx][ny]; q.push(nx*w+ny); } } } } int ans; void dfs(int tag,int val,int t) { if (t > L)return; if (ans == tot)return; if (tag > m&&val > ans){ ans = val; return; } for (int i = 0; i <= m + 1; ++i){ if (!vis2[i] && dis[tag][i]){ vis2[i] = 1; dfs(i, val + j[i], t + dis[tag][i]); vis2[i] = 0; } } } int main() { //freopen("in.txt", "r", stdin); scanf("%d", &t); for (int c = 1; c <= t; ++c){ memset(dis, 0, sizeof(dis)); tot = 0; scanf("%d %d %d %d", &w, &h, &L, &m); for (int i = 1; i <= m; ++i){ scanf("%d", &j[i]); tot += j[i]; } j[0] = 0; j[m + 1] = 0;//0代表入口,m+1代表出口,1~m代表宝石 for (int i = 0; i < h; ++i){ scanf("%s", g[i]); } for (int i = 0; i < h; ++i){ for (int j = 0; j < w; ++j){ if (g[i][j] == '@')bfs(i, j, 0); else if (g[i][j] == '<')bfs(i, j, m + 1); else if ('A' <= g[i][j] && g[i][j] <= 'J')bfs(i, j, g[i][j] - 'A' + 1); } } ans = -1; memset(vis2, 0, sizeof(vis2)); vis2[0] = 1; dfs(0,0,0); printf("Case %d:\n", c); if (ans >= 0)printf("The best score is %d.\n", ans); else printf("Impossible\n"); if (c <t)printf("\n"); } return 0; }