[关闭]
@Acqua 2019-01-27T13:12:33.000000Z 字数 1462 阅读 1038

POJ1185 炮兵阵地(Jan. 27th, 2019) 状压DP

动态规划

题目来源

题意

给定一个的棋盘,要求在棋盘中放置尽量多的棋子。棋盘中部分位置不能放置,且如果位置放置了棋子,那么位置±±±±都不能放置棋子。求最大可放置棋子数量。

思路

POJ3254,先预处理出每行的非法情况和合法情况,然后表示第行状态为,第行状态为的情况的答案。核心代码是枚举行、三重状态枚举。
初始化:全为,把符合条件的赋为状态的数量,可以避免对的特判。

代码

  1. // La Pluie Froid
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std;
  7. const int N = 100 + 3, M = 70 + 3;
  8. int p[N], n, m, dp[N][M][M], pluie[M], cal[M], t;
  9. char s[15];
  10. int Cal(int x){
  11. int res = 0;
  12. while(x){
  13. if(x & 1) res++;
  14. x >>= 1;
  15. }
  16. return res;
  17. }
  18. void Geography(){
  19. scanf("%d %d", &n, &m);
  20. for(int i = 1; i <= n; i ++){
  21. scanf("%s", s + 1);
  22. for(int j = 1; j <= m; j++){
  23. p[i] |= (s[j] == 'H') << (j - 1);
  24. }
  25. }
  26. }
  27. void Legal(){
  28. for(int i = 0; i < (1 << m); i ++){
  29. if((i & (i << 1)) || (i & (i << 2))) continue;
  30. pluie[++ t] = i;
  31. }
  32. for(int i = 1; i <= t; i ++){
  33. if(p[1] & pluie[i]) continue;
  34. dp[1][i][1] = Cal(pluie[i]); // 此处第三维的含义是:第i-1行全为0的情况在pluie数组中坐标为1。
  35. }
  36. }
  37. int main(){
  38. Geography();
  39. memset(dp, -1, sizeof(dp));
  40. Legal();
  41. for(int i = 2; i <= n; i ++){
  42. for(int j = 1; j <= t; j ++){
  43. if(pluie[j] & p[i]) continue;
  44. for(int k = 1; k <= t; k ++){
  45. if(pluie[k] & p[i - 1]) continue;
  46. if(pluie[j] & pluie[k]) continue;
  47. for(int l = 1; l <= t; l ++){
  48. if(pluie[l] & p[i - 2]) continue;
  49. if(pluie[j] & pluie[l]) continue;
  50. if(pluie[k] & pluie[l]) continue;
  51. if(dp[i - 1][k][l] == -1) continue;
  52. dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][l] + Cal(pluie[j]));
  53. }
  54. }
  55. }
  56. }
  57. int ans = 0;
  58. for(int i = 1; i <= t; i++){
  59. for(int j = 1; j <= t; j++){
  60. ans = max(ans, dp[n][i][j]);
  61. }
  62. }
  63. printf("%d", ans);
  64. return 0;
  65. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注