poj1185炮兵阵地 正确代码及错误代码分析

  Solution:状态压缩

因为设置炮兵的局限性(同行两炮兵相差要大于2),一行10个数最多有60种可能性(程序计算)

  其中判断可能性的好方法是:

if ((i & (i << 1))==0 && (i & (i << 2))==0
             && (i & (i >> 1))==0 && (i & (i >> 2))==0)

      代表不能有左1,左2,右1,右2相邻的1

行数相差2以上,两行互相之间没有影响

  

  if j,k,l不冲突

f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+v[j])

其中i为第i行,j为第i行的状态,k为第(i-1)行的状态,l为第(i-2)行的状态,v为在第i行的状态j可以设置的炮兵数

f[i][j][k]为前i行,以j,k状态下设置的最多的炮兵数,而第i行设置炮兵只与i-1,i-2行有关(前i行中)

时间复杂度:n*f(t)*f(t)*f(t)

f(t)为一行t个数,设置炮兵的可能性

n<=100,m<=10 即 100*60*60*60=21600000

事实上,由于地形的限制(山地不能建炮兵)和行与行之间的限制(同列两炮兵相差要大于2),时间复杂度小于此

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int max(int a,int b)
  5 {
  6     if (a>b)
  7         return a;
  8     else
  9         return b;
 10 }
 11
 12 int main()
 13 {
 14     //100*1024*1024
 15     int i,j,k,l,m,n,f[100][61][61],use[100][61],map[100]={0},s[100],v[1024]={0},ans=0,g=0;
 16     int er[11]={1,2,4,8,16,32,64,128,256,512,1024};
 17     char c;
 18     scanf("%d%d",&m,&n);
 19     scanf("%c",&c);
 20     for (i=0;i<m;i++)
 21     {
 22         for (j=n-1;j>=0;j--)
 23         {
 24             scanf("%c",&c);
 25             if (c==‘H‘)
 26                 map[i]+=er[j];
 27         }
 28         scanf("%c",&c);
 29     }
 30     /*
 31     for (i=0;i<m;i++)
 32         printf("%d\n",map[i]);
 33     printf("\n");
 34     */
 35     for (i=0;i<er[n];i++)
 36         if ((i & (i << 1))==0 && (i & (i << 2))==0
 37             && (i & (i >> 1))==0 && (i & (i >> 2))==0)
 38             {
 39                 ans++;
 40                 s[ans]=i;
 41                 j=i;
 42                 while (j)
 43                 {
 44                     j&=(j-1);
 45                     v[ans]++;
 46                 }
 47             }
 48     /*
 49     printf("ans=%d\n",ans);
 50     for (i=0;i<er[n];i++)
 51         printf("%d %d个 ",s[i],v[i]);
 52     */
 53     //init
 54     for (i=0;i<m;i++)
 55         use[i][0]=0;
 56     for (i=0;i<m;i++)
 57         for (j=1;j<=ans;j++)
 58             for (k=1;k<=ans;k++)
 59                 f[i][j][k]=0;
 60     //row
 61     for (i=0;i<m;i++)
 62         //each row , posibility
 63         for (j=1;j<=ans;j++)
 64             if ((map[i] & s[j])==0)
 65             {
 66                 use[i][0]++;
 67                 use[i][use[i][0]]=j;
 68
 69                 //编号 cur + bcur + bpre
 70                 if (i>=2)
 71                 {
 72                     for (k=1;k<=use[i-1][0];k++)
 73                         if ((s[j] & s[use[i-1][k]])==0)
 74                             for (l=1;l<=use[i-2][0];l++)
 75                                 if ((s[j] & s[use[i-2][l]])==0
 76                                     && (s[use[i-1][k]] & s[use[i-2][l]])==0)
 77                                         f[i][j][use[i-1][k]]=max(f[i][j][use[i-1][k]],f[i-1][use[i-1][k]][use[i-2][l]]+v[j]);
 78                 }
 79                 else if (i==1)
 80                 {
 81                     for (k=1;k<=use[i-1][0];k++)
 82                         if ((s[j] & s[use[i-1][k]])==0)
 83                             f[i][j][use[i-1][k]]=max(f[i][j][use[i-1][k]],f[i-1][use[i-1][k]][0]+v[j]);
 84                 }
 85                 else
 86                     f[i][j][0]=v[j];
 87
 88             }
 89     if (m!=1)
 90     {
 91         for (k=1;k<=use[m-1][0];k++)
 92             for (l=1;l<=use[m-2][0];l++)
 93                 if ((s[use[m-1][k]] & s[use[m-2][l]])==0)
 94                     g=max(g,f[m-1][use[m-1][k]][use[m-2][l]]);
 95     }
 96     else
 97     {
 98         for (k=1;k<=use[m-1][0];k++)
 99             g=max(g,f[m-1][use[m-1][k]][0]);
100     }
101     printf("%d\n",g);
102     /*
103     for (i=0;i<m;i++)
104     {
105         for (j=1;j<=ans;j++)
106             for (k=1;k<=ans;k++)
107                 //printf("f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k]);
108                 printf("%d ",f[i][j][k]);
109         printf("\n\n");
110     }
111         for (k=1;k<=use[m-1][0];k++)
112             for (l=1;l<=use[m-2][0];l++)
113                 printf("%d %d %d\n",s[use[m-1][k]],s[use[m-2][l]],f[m-1][use[m-1][k]][use[m-2][l]]);
114     */
115     return 0;
116 }

错误代码:

  if j,k,l不冲突

  f[i][j]=max(f[i][j],f[i-2][l]+v[k]+v[j]);

其中i为第i行,j为第i行的状态,k为第(i-1)行的状态,l为第(i-2)行的状态,v为在第i行的状态j可以设置的炮兵数

f[i][j]为前i行,以j状态下设置的最多的炮兵数

  但是l,k可能会发生冲突,在f[i-2][l]下,第(i-1)行不能用k状态

第三行,在第1,4个建炮兵情况下,

8 4

HPPH

PPPP-----是以右上方的P为基础,与第三行发生冲突

HPPH

PHHP

PHHP

HPPH

PPPP

HPPH

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 int max(int a,int b)
 5 {
 6     if (a>b)
 7         return a;
 8     else
 9         return b;
10 }
11
12 int main()
13 {
14     int i,j,k,l,m,n,f[100][1024],use[100][60],map[100]={0},s[100],v[1024]={0},ans=0,g=0;
15     int er[11]={1,2,4,8,16,32,64,128,256,512,1024};
16     char c;
17     scanf("%d%d",&m,&n);
18     scanf("%c",&c);
19     for (i=0;i<m;i++)
20     {
21         for (j=n-1;j>=0;j--)
22         {
23             scanf("%c",&c);
24             if (c==‘H‘)
25                 map[i]+=er[j];
26         }
27         scanf("%c",&c);
28     }
29     /*
30     for (i=0;i<m;i++)
31         printf("%d\n",map[i]);
32     printf("\n");
33     */
34     for (i=0;i<er[n];i++)
35         if ((i & (i << 1))==0 && (i & (i << 2))==0
36             && (i & (i >> 1))==0 && (i & (i >> 2))==0)
37             {
38                 ans++;
39                 s[ans]=i;
40                 j=i;
41                 while (j)
42                 {
43                     j&=(j-1);
44                     v[i]++;
45                 }
46             }
47     /*
48     printf("ans=%d\n",ans);
49     for (i=0;i<er[n];i++)
50         printf("%d ",v[i]);
51     */
52     for (i=0;i<m;i++)
53         use[i][0]=0;
54     for (i=0;i<m;i++)
55         for (j=0;j<er[i];j++)
56             f[i][j]=0;
57     //row
58     for (i=0;i<m;i++)
59     {
60         //each row , posibility
61         for (j=1;j<=ans;j++)
62             if ((map[i] & s[j])==0)
63             {
64                 use[i][0]++;
65                 use[i][use[i][0]]=s[j];
66                 if (i>=2)
67                 {
68                     for (k=1;k<=use[i-1][0];k++)
69                         if ((s[j] & use[i-1][k])==0)
70                             for (l=1;l<=use[i-2][0];l++)
71                                 if ((s[j] & use[i-2][l])==0
72                                     && (use[i-1][k] & use[i-2][l])==0)
73         f[i][s[j]]=max(f[i][s[j]],f[i-2][use[i-2][l]]+v[use[i-1][k]]+v[s[j]]);
74                 }
75                 else if (i==1)
76                 {
77                     for (k=1;k<=use[i-1][0];k++)
78                         if ((s[j] & use[i-1][k])==0)
79         f[i][s[j]]=max(f[i][s[j]],f[i-1][use[i-1][k]]+v[s[j]]);
80                 }
81                 else
82                     f[i][s[j]]=v[s[j]];
83             }
84     }
85     for (i=1;i<=use[m-1][0];i++)
86         g=max(g,f[m-1][use[m-1][i]]);
87     printf("%d\n",g);
88     /*
89     for (i=0;i<m;i++)
90     {
91         for (j=0;j<er[n];j++)
92             printf("%d ",f[i][j]);
93         printf("\n");
94     }
95     */
96     return 0;
97 }
时间: 2024-09-30 00:03:08

poj1185炮兵阵地 正确代码及错误代码分析的相关文章

poj1185炮兵阵地

#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string.h> #include <string> using namespace std; const int MAXN = 100 + 1; //阵地行数 const int MAXM = 10 + 1; //阵地列数 const int State_Num

poj1185炮兵阵地状压dp

压前两行的状态很容易想到,但是 直接搞  (1<<10) * (1<<10)  空间时间都明显受不了, 但是经过高人指点,你会发现:枚举每一行可行的状态,其实并不多,预先打表处理,不用 1->(1<<10)枚举每一种状态.. 然后记忆化搜就ok了. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include &

[poj1185]炮兵阵地_状压dp

炮兵阵地 poj-1185 题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数. 注释:n<=100,m<=10.然后只能在平原的地方建立炮兵. 想法:第2到状压dp,++.这题显然是很经典的.设状态dp[i][j][k]表示第i行的状态为j,i-1行的状态为k的最多炮兵数.在转移时,枚举所有的合法炮兵排列(此处的合法数目是根据一行全为平原的时候能放置的合法炮兵数目),然后内层循环枚举dp[i-1]的i-1状态,进行特判更新即可.统计答案时,我们只需对于dp[n]的所有可能状态求最大值

POJ1185 炮兵阵地 状态压缩DP

B - 炮兵阵地 Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-06-29) Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用&quo

POJ1185炮兵阵地(状态压缩DP)

POJ飞翔.数据弱 ZQOJ飞翔 数据强 Description 司令部的将军们打算在N×M的网格地图上部署他们的炮兵部队.一个N×M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,

[POJ1185]炮兵阵地

试题描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格均攻击不到.从图上可见

[POJ1185]炮兵阵地(状压DP)

题目链接:http://poj.org/problem?id=1185 这个和之前的不一样,在于某个点影响的范围是两格.那么dp(cur,pre,i)表示第i行状态为cur,i-1行状态为pre时可以有多少种放法.转移的时候枚举ppre,就是i-2行即可.照葫芦画瓢 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7 ┓┏┓┏┓┃ 8 ┛┗┛┗┛┃ 9 ┓┏┓┏┓┃ 10 ┛┗┛┗┛┃ 1

[状压dp]POJ1185 炮兵阵地

中文题 题意不再赘述 对于中间这个“P” 根据dp的无后效性 我们只需考虑前面的 就变成了 只需考虑: 也就是状压前两行 具体与HDOJ的4539类似: 看HDOJ 4539 仅仅是共存状态的判断不同 1 //#include <bits/stdc++.h> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using n

《笨办法学python第三版》习题26,原错误代码及正确代码

#import ex25 1 def break_words(stuff): 2 """This function will break up words for us.""" 3 words = stuff.split(' ') 4 return words 5 6 def sort_words(words): 7 """Sorts the words.""" 8 return sor