题目链接:收集水晶
一眼看过去,觉得是普通的bfs,初始位置有两个。仔细想了想...好像如果这样的话..........【不知道怎么说...T_T】
dp[12][12][12][12][210] 中dp[x1][y1][x2][y2][t] =value 表示t时刻人和影子分别到x1,y1 和x2, y2位置的时候得到的最大价值是value。
然后呢,因为每个点的状态一定是由它相邻的状态确定的,所以由dp[0][0][0][0][0] = 0就可以得到所有的状态,中间记录最大值即为ans。
这是暴力遍历所有状态,附代码:
// 暴力大法. #include <stdio.h> #include <string.h> #include <iostream> using namespace std; char mp[12][12]; int gem[210][12][12]; int dp[12][12][12][12][210]; int dir[5][2] = {1, 0, -1, 0, 0, 1, 0, -1, 0, 0}; int n, m; bool check(int a, int b) { if (a>=0 && a<n && b>=0 && b<m && mp[a][b] == '.') return true; return false; } int main() { int t; cin >> t; while(t--) { cin >> n >> m; for (int i=0; i<n; ++i) { for (int j=0; j<m; ++j) { cin >> mp[i][j]; } } int p; int maxt = 0; memset(gem, 0, sizeof(gem)); cin >> p; for (int i=0; i<p; ++i) { int t, x, y, v; cin >> t >> x >> y >> v; x--; y--; gem[t][x][y] += v; maxt = max(maxt, t); } memset(dp, -1, sizeof(dp)); dp[0][0][0][0][0] = 0; int ans = 0; for (int t=1; t<=maxt; ++t) { for (int x1=0; x1<n; ++x1) { for (int y1=0; y1<m; ++y1) { for (int x2=0; x2<n; ++x2) { for (int y2=0; y2<m; ++y2) { if (dp[x1][y1][x2][y2][t-1] != -1) { for (int k=0; k<25; ++k) { int x11 = x1 + dir[k/5][0]; int y11 = y1 + dir[k/5][1]; int x22 = x2 + dir[k%5][0]; int y22 = y2 + dir[k%5][1]; if (check(x11, y11) && check(x22, y22)) { if (x11 == x22 && y11 == y22) dp[x11][y11][x22][y22][t] = max(dp[x11][y11][x22][y22][t], dp[x1][y1][x2][y2][t-1] + gem[t][x11][y11]); else dp[x11][y11][x22][y22][t] = max(dp[x11][y11][x22][y22][t], dp[x1][y1][x2][y2][t-1] + gem[t][x11][y11] + gem[t][x22][y22]); ans = max(ans, dp[x11][y11][x22][y22][t]); //cout << ans << "====\n"; } } } } } } } } cout << ans << endl; } return 0; }
然后,也可以用bfs+记忆化搜索...............................思想是一样的,也是遍历所有的状态,每次遇见一个新的,可以由它到达新的位置的时候,就加入队列。当前状态取当前值和想邻点到达值得max。
附代码:
#include <queue> #include <stdio.h> #include <string.h> #include <iostream> using namespace std; char mp[12][12]; int gem[210][12][12]; int dp[12][12][12][12][210]; int ans; int tmax; int dir[5][2] = {1, 0, -1, 0, 0, 1, 0, -1, 0, 0}; int n, m; struct Node { int x1, y1, x2, y2, t; Node (int x1, int y1, int x2, int y2, int t) { this->x1 = x1, this->y1 = y1; this->x2 = x2, this->y2 = y2; this->t = t; } Node () { } }node[200]; bool check(Node a) { if (a.x1 >= 0 && a.x1 < n && a.y1 >= 0 && a.y1 < m && a.x2 >= 0 && a.x2 < n && a.y2 >= 0 && a.y2 < m && mp[a.x1][a.y1] == '.' && mp[a.x2][a.y2] == '.') return true; return false; } void bfs(int x1, int y1, int x2, int y2, int t) { queue<Node> que; Node now(x1, y1, x2, y2, t); que.push(now); dp[x1][y1][x2][y2][t] = 0; while(!que.empty()) { now = que.front(); que.pop(); if (now.t > tmax) continue; for (int i=0; i<25; ++i) { Node nxt; nxt.x1 = now.x1 + dir[i/5][0]; nxt.y1 = now.y1 + dir[i/5][1]; nxt.x2 = now.x2 + dir[i%5][0]; nxt.y2 = now.y2 + dir[i%5][1]; nxt.t = now.t + 1; if (check(nxt)) { int tot = dp[now.x1][now.y1][now.x2][now.y2][now.t] + gem[nxt.t][nxt.x1][nxt.y1] + gem[nxt.t][nxt.x2][nxt.y2]; if (nxt.x1 == nxt.x2 && nxt.y1 == nxt.y2) tot -= gem[nxt.t][nxt.x1][nxt.y1]; if (dp[nxt.x1][nxt.y1][nxt.x2][nxt.y2][nxt.t] < tot) { if (dp[nxt.x1][nxt.y1][nxt.x2][nxt.y2][nxt.t] == -1) { que.push(nxt); } dp[nxt.x1][nxt.y1][nxt.x2][nxt.y2][nxt.t] = tot; ans = max(ans, tot); } } } } } int main() { int T; cin >> T; while(T--) { ans = 0; cin >> n >> m; memset(dp, -1, sizeof(dp)); for (int i=0; i<n; ++i) { for (int j=0; j<m; ++j) { cin >> mp[i][j]; } } int p; cin >> p; tmax = 0; memset(gem, 0, sizeof(gem)); for (int i=0; i<p; ++i) { int t, x, y, v; cin >> t >> x >> y >> v; tmax = max(t, tmax); x--; y--; gem[t][x][y] += v; } bfs(0, 0, 0, 0, 0); cout << ans << endl; } return 0; }
因为没有想到两个状态一起表示,所以整个题都没什么感觉,瞄了一眼就过去了.