[关闭]
@Acqua 2019-01-28T11:46:59.000000Z 字数 2522 阅读 993

HDU3681 Prison Break(Jan. 28th, 2019) 状压DP BFS

动态规划 二分答案 标准

题目来源

题意

给定的矩阵,要求遍历指定点(“”)。遍历耗电,途中有充电点(可充满),求能达到要求的最小电池容量。

思路

显然状压搜索二分答案。
首先搜索,首选广搜记忆化,伪代码:

  1. 枚举每一个点{
  2. 记忆化数组赋为inf
  3. 入队;
  4. 广搜{
  5. 取出队头;弹出队头;
  6. 如果答案较记忆化数组不优,跳过;
  7. 枚举扩展点{
  8. 若不在区域内,跳过;
  9. 若不可通过(“D”),跳过;
  10. 入队;
  11. }
  12. }
  13. 枚举每一个点{
  14. 记录距离;
  15. }
  16. }

似乎没出问题。
二分答案是模板直接跳过。
检验函数显然是一个问题。设代表在状态下处于点时的最大电量。
伪代码:

  1. dp[0][0]=检验值;
  2. 枚举状态{
  3. 枚举前一点{
  4. 如果状态不包含前一点,跳过;
  5. 如果前置状态未计算,跳过;
  6. 如果当前状态包含所有开关及起点,就返回1
  7. 枚举当前点{
  8. 如果状态包括当前点,跳过;
  9. 如果当前点与前一点不连通,跳过;
  10. 如果当前点是电池,就充满电;
  11. TSP经典转移方程;
  12. }
  13. }
  14. 如果状态包含了所有开关,就统计最大电量;
  15. }
  16. 返回0

修改:把起点包含进去。

反思

  1. 算是个小小的胜利,但是对来说,能算得上什么呢?可笑至极。我已经失去她了
  2. 证实:“标程算法自己的程序”的流程是可行的。

代码

  1. // La Pluie
  2. #include<queue>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<iostream>
  6. #include<algorithm>
  7. using namespace std;
  8. struct point{int x, y, r;} p[16];
  9. struct node{int x, y, d;};
  10. char c[20];
  11. int dis[16][16], dp[65536][16], t, mem[16][16], n, m, map[16][16], tgs, start;
  12. int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1}, inf = 0x3f3f3f3f;
  13. bool ctrl(int x, int y){return x <= n && x >= 1 && y <= m && y >= 1;}
  14. void bfs(node s){
  15. queue <node> q; q. push(s);
  16. while(!q. empty()){
  17. node u = q. front(); q. pop();
  18. int x = u. x, y = u. y, d = u. d;
  19. if(mem[x][y] < d) continue; mem[x][y] = d;
  20. for(int i = 0; i < 4; i++){
  21. int nx = x + dx[i], ny = y + dy[i];
  22. if(!ctrl(nx, ny)) continue;
  23. if(map[nx][ny]) continue;
  24. q. push((node){nx, ny, d + 1});
  25. }
  26. }
  27. }
  28. bool author(int d){
  29. dp[1 << start - 1][start] = d;
  30. for(int i = 0; i < (1 << t); i++){
  31. for(int j = 1; j <= t; j++){ // previous
  32. if(!(i & (1 << j - 1))) continue;
  33. if(dp[i][j] == -1) continue;
  34. if((i & tgs) == tgs) return 1;
  35. for(int k = 1; k <= t; k++){ // present
  36. if(i & (1 << k - 1)) continue;
  37. if(dis[j][k] == inf) continue;
  38. if(dp[i][j] < dis[j][k]) continue;
  39. dp[i | (1 << k - 1)][k] = max(dp[i | (1 << k - 1)][k], dp[i][j] - dis[j][k]);
  40. if(p[k]. r == 2) dp[i | (1 << k - 1)][k] = d;
  41. }
  42. }
  43. }
  44. return 0;
  45. }
  46. int main(){
  47. while(~scanf("%d %d", &n, &m) && (n || m)){
  48. memset(map, 0, sizeof(map)); tgs = 0, t = 0;
  49. for(int i = 1; i <= n; i++){
  50. scanf("%s", c + 1);
  51. for(int j = 1; j <= m; j++){
  52. if(c[j] == 'F') p[++t] = (point){i, j, 1}, tgs |= 1 << t - 1, start = t;
  53. if(c[j] == 'G') p[++t] = (point) {i, j, 2};
  54. if(c[j] == 'Y') p[++t] = (point) {i, j, 3}, tgs |= 1 << t - 1;
  55. if(c[j] == 'D') map[i][j] = 1;
  56. }
  57. }
  58. memset(dis, 0x3f, sizeof(dis));
  59. for(int i = 1; i <= t; i++){
  60. memset(mem, 0x3f, sizeof(mem));
  61. bfs((node){p[i]. x, p[i]. y, 0});
  62. for(int j = 1; j <= t; j ++){
  63. dis[i][j] = dis[j][i] = mem[p[j]. x][p[j]. y];
  64. }
  65. }
  66. // for(int i = 0; i <= t; i++){printf("p[%d] = (%d, %d, %d)\n", i, p[i]. x, p[i]. y, p[i]. r);}
  67. // for(int i = 0; i <= t; i++){for(int j = 0; j <= t; j ++){printf("%d ", dis[i][j]);}printf("\n");}
  68. int l = 0, r = n * m, ans = -1;
  69. while(l <= r){
  70. int mid = l + r >> 1;
  71. memset(dp, -1, sizeof(dp));
  72. // printf("mid = %d\n", mid);
  73. if(author(mid)) ans = mid, r = mid - 1;
  74. else l = mid + 1;
  75. }
  76. printf("%d\n", ans);
  77. }
  78. return 0;
  79. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注