1. 为何状态压缩:
棋盘规模为n*m,且m≤10,如果用一个int表示一行上棋子的状态,足以表示m≤10所要求的范围。故想到用int s[num]。至于开多大的数组,可以自己用DFS搜索试试看;也可以遍历0~2^m-1,对每个数值的二进制表示进行检查;也可以用数学方法(?)
2. 如何构造状态:
当然,在此之前首先要想到用DP(?)。之后,才考虑去构造状态函数f(...)。
这里有一个链式的限制
:某行上的某个棋子的攻击范围是2。即,第r行的状态s[i],决定第r-1行只能取部分状态s[p];同时,第r行的状态s[i],第r-1行状态s[p],共同决定第r-2行只能取更少的状态s[q]。当然,最后对上面得到的候选s[i], s[p], s[q],还要用地形的限制去筛选一下即可。
简言之,第r行的威震第r-2行,因此在递推公式(左边=右边)中,必然同时出现r,和r-2两个行标;由于递推公式中行标是连续出现的,故在递推公式中必然同时出现r, r-1和r-2三个行标。由于在递推公式中左边包含一个f(...),右边包含另一个f(...),根据抽屉原理,r, r-1, r-2中至少有两个在同一个f(...)中,因此状态函数中必然至少包括相邻两行的行号作为两个维度。这就是为什么状态函数要涉及到两(相邻的)行,而不是一行。能想到的最简单形式如下:
dp[r][i][p]:第r行状态为s[i],第r-1行状态为s[p],此时从第0行~第r行棋子的最大数目为dp[r][i][p]
递推公式:
s[p]影响到s[q]的选取
----
| |
dp[r][i][p]=max{dp[r-1][p][q]}+sum[j], 其中sum[j]是状态s[j]中1的个数
| | |
---- |
s[i]影响到s[p]的选取 |
| |
----------------------------
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAX(a,b) (a)>(b)?(a):(b)
using namespace std;
int dp[105][65][65]; //d[i][j][k]: “第i行状态是s[j],第i-1行状态是s[k]”的
int s[105]; //一行的状态选择s[0], s[1], ... , s[k-1]
int n,m; //n行×m列
int k; //一行的所有状态数
int map[105]; //'H''P'地图map[0]~map[n-1],地图每一行map[line]: 1001 表示HPPH
int sum[105];
/*
很久就看推荐题目有这个了,一直没做,因为看了好几次没看懂,都说dp,这几天看了状态压缩后明白了,其实就是用
二进制来表示各个位置的状态然后进行枚举,把状态放进数组里就行,在这里用dp[i][j][k]表示第i行,当前j状态,
i-1行是k状态时候的最大炮数 dp[i][j][k]=MAX(dp[i][j][k],dp[i-1][k][p]+sum[j])
CAUTION:
1. 所有下标均从0开始
2. m<=10保证了可以用一个int存储一行的状态
*/
//状态s[x]是否造成行冲突
bool ok(int x)
{
if(x&(x<<1))return false;
if(x&(x<<2))return false;
return true;
}
//状态s[x]下有多少个1
int getsum(int x)
{
int num=0;
while(x>0)
{
if(x&1)num++;
x>>=1;
}
return num;
}
void find()
{
memset(s,0,sizeof(s));
for(int i=0;i<(1<<m);i++) //i枚举所有m位的二进制数
{
if(ok(i))
{
s[k]=i;
sum[k++]=getsum(i);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
memset(dp,-1,sizeof(dp));
int i;
for(i=0;i<n;i++){
for(int j=0;j<m;j++){
char tmp;
cin>>tmp;
if(tmp=='H')map[i]=map[i]|(1<<j);//把第i行原始状态取反后放入map[i]
}
}
k=0;
find();
//1. 初始化第0行状态(只考虑有效状态,无效状态为-1)
for(i=0;i<k;i++)
if(!(s[i]&map[0])) //s[i]为1的位如果对应平原(0),则&运算后为0
dp[0][i][0]=sum[i];
//2. 计算第1~n-1行状态(碰到无效状态,continue)
for(int r=1;r<n;r++)
{
for(int i=0;i<k;i++)//枚举第r行的状态 s[i]
{
if(map[r]&s[i]) continue; //通过地形排除部分第r行的状态
for(int p=0;p<k;p++) //枚举第r-1行状态 s[p]
{
if(s[i] & s[p]) continue; //r与r-1没有想接触的
for(int q=0;q<k;q++) //枚举第r-2行状态s[q]
{
if(s[p] & s[q]) continue; //Sam:这行是我加的
if(s[i] & s[q]) continue; //r与r-2行没有接触的
if(dp[r-1][p][q]==-1) continue; //所有不可能的情形dp[i][j][k]都为-1(初始化的值)
dp[r][i][p]=MAX(dp[r][i][p],dp[r-1][p][q]+sum[i]);
}
}
}
}
int ans=0;
for(i=0;i<k;i++)
for(int j=0;j<k;j++)
ans=MAX(ans,dp[n-1][i][j]);
printf("%d\n",ans);
}
system("pause");
return 0;
}
- 大小: 5.9 KB
分享到:
相关推荐
标题“POJ 1185 炮兵阵地”是一个编程竞赛问题,源自著名的在线判题系统POJ(Programming Online Judge)。这个问题旨在测试参赛者的算法设计和编程能力。描述中提到“数据略弱”,意味着POJ原题目的数据范围可能较...
【标题】"POJ2002-Squares"是一个经典的计算机编程题目,源自北京大学的在线判题系统(POJ,即PKU Online Judge)。这个题目主要涉及到算法设计和实现,尤其是数学和动态规划方面的知识。 【描述】"解题报告+AC代码...
描述“北大POJ3253-POJ3253-Fence Repair【STL优先队列】解题报告+AC代码”表明这是一篇关于如何解答此题目的报告,其中包含了通过AC(Accepted)状态的代码,即代码已经成功通过了所有测试用例。解题报告通常会涵盖...
标题中的“炮兵阵地(POJ-1185)”是一个编程竞赛题目,源自国内著名的在线编程平台POJ(编程之美)。这类题目通常要求参赛者编写程序来解决特定的算法问题。在这个案例中,我们可能面临的是一个与数学、策略或者...
【标题】"POJ1426-Find The Multiple【BFS+同余模】"是一道来源于北京大学在线编程平台POJ的算法题目,主要涉及到了广度优先搜索(BFS)与同余模运算的知识点。这道题目要求解决的是寻找一个整数的倍数问题,可能...
标题中的"POJ3411-Paid Roads【class】"指的是一个编程竞赛问题,源自北京大学的在线评测系统POJ(Problem Online Judge)。这个题目可能涉及到道路付费的问题,需要通过编程来解决。"class"在这里可能指的是在解决...
【标题】"POJ3020-Antenna Placement"是一个经典的计算机编程竞赛题目,源自北京大学的在线评测系统POJ(PKU Online Judge)。这个题目挑战了参赛者在算法设计和实现上的能力。 【描述】"解题报告+AC代码"意味着这...
《POJ 1000 - 2000 部分题目 官方分类》 编程竞赛,特别是在线判题系统(如POJ,即Problem Online Judge)中的题目,是提升编程技能和算法理解的重要途径。POJ 1000 - 2000 是一个涵盖广泛的题目区间,包含了大量的...
【标题】"POJ1015-Jury Compromise" 是一个编程竞赛题目,主要涉及的是动态规划(Dynamic Programming, 简称DP)的算法应用。动态规划是一种解决复杂问题的有效方法,它通过将问题分解成子问题,并存储子问题的解来...
【标题】"POJ1837-Balance"是一个在线编程竞赛题目,源自著名的编程练习平台POJ(Programming Online Judge)。这个题目旨在测试参赛者的算法设计和实现能力,特别是处理平衡问题的技巧。 【描述】"解题报告+AC代码...
《POJ1184-Smart typist:深入解析搜索与状态压缩算法》 在编程竞赛的世界里,POJ1184是一个经典的题目,它挑战了程序员对搜索算法和状态压缩技术的理解与应用。本篇文章将围绕这个题目,详细阐述其背后的算法思想...
这是魔兽世界终极版POJ的-测试数据,找了好久才找到的。 本来想设置为0积分,但是它居然自动收费(o_ _)ノ。 看传送门:https://pan.baidu.com/s/1cCIwW8psGDASu2JdZawG3Q
【压缩包子文件的文件名称列表】中的"POJ2299-Ultra-QuickSort.cpp"是一个C++源代码文件,它包含了用C++语言实现的解题代码。".cpp"扩展名表明代码是用C++编写的,C++是一种静态类型、编译式的通用编程语言,特别...
【压缩包子文件的文件名称列表】中,"POJ3080-Blue Jeans.cpp" 是提交给POJ平台的AC代码,可能包含了上述的动态规划解法,使用C++语言实现。"POJ3080-Blue Jeans.doc" 可能是解题报告文档,详细解释了解题过程和思路...
【标题】"POJ1010-STAMPS"是一个编程题目,来源于北京大学的在线判题系统POJ(Problem Set of Peking University),这是一处训练程序员算法技能和编程能力的平台。该题目旨在考察参赛者对动态规划或贪心算法的理解...
【标题】"POJ1258-Agri-Net【Prim】" 是一个编程竞赛题目,来源于北京大学的在线评测系统POJ(Problem Online Judge)。这个题目主要涉及到图论中的一个重要算法——普里姆(Prim)算法。 【描述】"北大POJ1258-...
对于此题,可能的状态转移方程可以是dp[i][j] = min(dp[i-1][k]+cost[i-1][j-k]),其中cost[i-1][k]表示前i-1个文件用k台碎纸机处理的时间。 3. **剪枝**:为了减少不必要的计算,我们可以在动态规划过程中加入剪枝...
【标题】"POJ2503-Babelfish"是一个来自北京大学在线判题系统(POJ,Problem Online Judge)的编程题目。该题目要求参赛者编写程序解决特定的算法问题,通过编程语言实现,然后提交代码以供系统自动评测。 【描述】...
标题“POJ3414-Pots”是一个编程竞赛题目,源自北京大学的在线判题系统POJ(Problem Online Judge)。这个题目主要考察的是算法设计和实现能力,通常涉及计算机科学中的数据结构和算法知识。 解题报告是参赛者在...
【压缩包子文件的文件名称列表】中的"POJ1003-Hangover.cpp"表明提供的解决方案是用C++编程语言编写的。C++是一种静态类型、编译式的通用编程语言,以其强大的性能和灵活性在算法竞赛中被广泛使用。另一个文件"POJ...