poj 1185解题总结

  算是本人的第一篇博客吧,以前从来没想过写博客总结这事儿,都是看别人博客里的资料。不过慢慢觉得是个好习惯,很多学到的东西也应该总结总结,会有新的收获,所以也就行动起来。其实我做poj的题目纯粹是练手学算法,没有什么参加竞赛的条件和水平,比较菜,只能说自我提高的事儿。废话不多说了,试试走起。

  poj1185题意大致是说有一个N*M的网格方阵,里面有平原和山地,山地不能放炮兵部队,平原可以,同时炮兵部队之间至少要隔两个网格以免误伤,问最多部署多少部队。M<=10,N<=100。

  输入第一行是网格方阵的行和列,后面是每一行的地形情况。输出就是最大的部队数。

  刚开始拿到题目反正我是不怎么会,毕竟算法都是做题现学,没系统学过算法,以前做过一题动态规划的题目,但是手还是太生,没活学活用起来。看看discuss,大概知道这个题目的主要知识点,然后上网现学。状态压缩的动态规划其实还理解的不是很透彻,主要就是讲原来网格的布置状态每行有2M种,N行就总共有2M*N种状态,算起来还是很庞大的。所以要将状态压缩,使状态空间的可能性越少越好,这样表示起来存储空间才能够。然后再找到可以利用此状态空间迭代表示整个网格方阵的状态的方程,或者说找到压缩后的状态和之前的庞大状态空间之间的关系,然后就可以考虑细节编程了。

  具体到这个题目的例子,压缩后的状态空间可以表示成当前的行i,上一行i-1,上上行i-2。第i行的状态只受第i-1和第i-2行的限制,所以考虑了i-1和i-2行,就可以列出所有的i行状态。这样可以用dp[i][a][b]的三维数组来表示第i行状态时a,上一行是b状态时的最大部队数。然后再表示出这三行的关系:dp[i][a][b] = max{dp[i-1][b][c] + get[i]},其中dp[i-1][b][c]表示第i-1行是状态b,i-2行是状态c时的最大部队数。这样,就可以用这种方式,表示出原来的那么多状态,节省了空间时间。

  刚开始的时候我总觉得应该是四维数组,即i行,i行状态,i-1行状态,i-2行状态,毕竟这样才能表示出第i行是由前两行状态决定的嘛~不过后来看到别人都“不约而同”的使用三维数组,我再仔细琢磨琢磨,才明白了点儿。这样表示出来的是第i行在前两行分别是b,c状态下,自身是a状态的部队数结果,而不是最大部队数。通过统计所有b状态下,i-2行的状态情况,得出的第i行在a状态下最大部队数,就可以通过对i-2行的统计和省略i-2行的状态表示。实际上a表示上一行,b表示上上行也是可以的,只不过这样就是把i行所有状态进行统计比较,选出最大的保存下来而已。

  具体状态的表示形式和细节问题可以参见代码注释,上面说的还是太抽象,毕竟自己懂得也不是很深。还得做题巩固加深理解。

  1 import java.io.BufferedReader;
  2 import java.io.FileInputStream;
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.io.InputStreamReader;
  6 
  7 public class Poj1185 {
  8 
  9     static int map[]  = new int[105];//网格方阵,每一个整数数都可以表示成二进制数,用来表示每一行的状态,比如1000000000表示这一行第1位有部队
 10     static int dp[][][] = new int[105][65][65];//状态表示:第i行,第i-1状态a,第i-2行状态b。由于每一行都需要保持部队之间大于等于两个位置,所以每一行
 11     //的状态最多并不是2的10次方,1024个,而是60个。可以通过dfs枚举所有合法的状态出来。
 12     static int status[] = new int[65];//存放一行的所有状态
 13     static int get[] = new int[65];//存放每一个状态对应的部队数
 14     static int statusNum = 0;
 15     public static void main(String[] args) throws IOException {
 16         // TODO Auto-generated method stub
 17         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 18         String inputStr = br.readLine();
 19         String[] inputs = inputStr.split(" ");
 20         int N = Integer.parseInt(inputs[0]);//行数
 21         int M = Integer.parseInt(inputs[1]);//列数
 22         for(int i = 0;i<N;i++)
 23         {
 24             String input = br.readLine();
 25             for(int j = M-1;j>=0;j--)
 26             {
 27                 
 28                 if(input.charAt(M-1-j)=='P')
 29                 {
 30                     map[i] = map[i]&(~(0<<j));//位运算,某一位置成0
 31                     
 32                 }else
 33                 {
 34                     map[i] = map[i]|(1<<j);
 35                 }
 36                 
 37             }
 38             
 39         }
 40         map[N+1] = 1023;
 41         map[N+2] = 1023;
 42         
 43         Dfs(M);//枚举一行在不考虑山的前提下所有合法状态
 44         Counter(M);//计算每一个合法状态的部队数
 45         int maxall = 0;
 46         int resultall = 0;
 47         
 48         for ( int i = 0; i < 105; ++i )//初始化
 49                {
 50                    for ( int j = 0; j < 65; ++j )
 51                    {
 52                        for ( int k = 0; k < 65; ++k )
 53                       {
 54                          dp[i][j][k] = -2;//-2为初始未计算状态
 55                       }
 56                    }
 57                }
 58 
 59         maxall = dp(N+1,0,0);
 60         System.out.println(maxall);
 61         
 62         
 63         
 64     }
 65     
 66     //当前行,当前状态,上一行状态
 67     static int dp(int i,int a,int b)
 68     {
 69         if(i > 1)
 70         {
 71             if(dp[i][a][b]==-2)
 72             {
 73                 if(((map[i]&status[a])==0)&&((status[a]&status[b])==0))//判断当前状态与地图是否相符,当前状态与上一行是否相符
 74                 {
 75                     int max = -1;
 76                     int result = -1;
 77                     for(int x = 0;x<statusNum;x++)
 78                     {
 79                         if((status[x]&status[a])==0)//当前状态与上上一行是否冲突
 80                         {
 81                             int temp = dp(i-1,b,x);
 82                             if(temp==-1)continue;
 83                             result = temp + get[a];
 84                             if(result>max)
 85                             {
 86                                 max = result;
 87                             }
 88                         }
 89                     }
 90                     dp[i][a][b] = max;
 91                     
 92                 }else
 93                 {
 94                     dp[i][a][b] = -1;
 95                     
 96                 }
 97             }
 98             
 99         }else if(i==1)//只剩第1行和第0行
100         {
101             if(dp[i][a][b]==-2)
102             {
103                 if(((map[i]&status[a])==0)&&((status[a]&status[b])==0)&&((map[i-1]&status[b])==0))
104                 {
105                     dp[i][a][b] = get[b]+get[a];
106                     
107                 }else
108                 {
109                     dp[i][a][b] = -1;
110                     
111                 }
112             }
113         }
114         return dp[i][a][b];
115     }
116     
117     static void Dfs(int M)
118     {
119         int num = (int) (Math.pow(2, M)-1);
120         for(int i = 0;i<=num;i++)
121         {
122             boolean isOkay = true;
123             for(int j = 0;j<M-1;j++)
124             {
125                 
126                 if((((i>>j)&1)==1)&&(((i>>(j+1))&1)==1)||(((i>>j)&1)==1)&&(((i>>(j+2))&1)==1))//两个1之间至少隔2个0
127                 {
128                     isOkay = false;
129                     break;
130                 }
131                 
132             }
133             if(isOkay)
134             {
135                 status[statusNum++] = i; 
136             }
137         }
138         
139     }
140     
141     static void Counter(int M)
142     {
143         for(int i = 0;i<statusNum;i++)
144         {
145             int onenumber = 0;
146             for(int j = 0;j<M;j++)
147             {
148                 if(((status[i]>>j)&1)==1)
149                 {
150                     onenumber++;
151                 }
152             }
153             get[i] = onenumber;
154         }
155     }
156 
157 }

 

转载于:https://www.cnblogs.com/kiwihy/p/3929560.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值