博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
poj 1185解题总结
阅读量:4320 次
发布时间:2019-06-06

本文共 4558 字,大约阅读时间需要 15 分钟。

  算是本人的第一篇博客吧,以前从来没想过写博客总结这事儿,都是看别人博客里的资料。不过慢慢觉得是个好习惯,很多学到的东西也应该总结总结,会有新的收获,所以也就行动起来。其实我做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
=0;j--) 26 { 27 28 if(input.charAt(M-1-j)=='P') 29 { 30 map[i] = map[i]&(~(0<
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
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 }else108 {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
>j)&1)==1)&&(((i>>(j+1))&1)==1)||(((i>>j)&1)==1)&&(((i>>(j+2))&1)==1))//两个1之间至少隔2个0127 {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
>j)&1)==1)149 {150 onenumber++;151 }152 }153 get[i] = onenumber;154 }155 }156 157 }

 

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

你可能感兴趣的文章
MYSQL GTID使用运维介绍(转)
查看>>
Fail to start neutron-server
查看>>
景安快运挂在磁盘-支持宝塔
查看>>
word中交叉引用不能更新的解决方法
查看>>
高性能HTTP加速器Varnish(概念篇)
查看>>
Linux 如何写makefile文件
查看>>
flutter_webview_plugin 无法加载网页的异常处理
查看>>
bloc控制读写文件
查看>>
微信小程序
查看>>
洛谷 P1059 明明的随机数
查看>>
window自动任务实现数据库定时备份
查看>>
Windows 7 Ultimate(旗舰版)SP1 32/64位官方原版下载(2011年5月12日更新版)
查看>>
javascript操作cookie
查看>>
深入理解HTTP协议(转)
查看>>
NHibernate讲解
查看>>
剑指offer-二叉树中和为某一值的路径
查看>>
spark算子
查看>>
(转)Linux服务器SNMP常用OID
查看>>
USB各种模式 解释
查看>>
数据访问-----ADO.NET 小结和练习
查看>>