假期训练总结
经过四个星期的训练,暑假集训也在此告一段落了。在此期间,进行了DP专题的学习,不得不说,进度太慢。一方面是由于专题本身的难度,另一方面则是我们知识的不足,还有缺少硬怼的精神。嘛,总之,吸取教训,今后改正,也是收获之一吧。下面对DP专题做一下简略的总结。
一,状压DP
目前已知题型:
1,图表类型问题
2,TSP问题。
1,图表类型问题
etc:炮兵问题,放牛问题,矩阵问题,排兵布阵问题(状态多为两种:选与不选用0、1存储)
所求结果,最多可放置多少个;最多有几种放置方法;最大方格中所取数之和
主要模块
1,存图,map[i]|=(1<<j)或者map[i]+=1<<(j-1)其中存储的是不能放置的位置,即1为无法放置的,0为能
放置的。原因见2.
2,开个数组存储可进行选择的状态,1代表可选的,0代表不可选的。这样在与map“&”时,取非即为可能的情况
0,1;1,0;0,0都有可能,若条件1将1设为能放置,0为不能放置,这样可能漏掉0,0情况。
etc:
int cnt=0;
for(int i=0;i<(1<<k);i++){
if(判断条件){
num[cnt++]=i;
}
}
3,计算二进制状态中有几个1的模板
int res=0;
while(x/*用十进制存储的状态*/){
res++;
x&=(x-1);
}
4,滚动数组,表格问题一般之与上一行状态有关,此时,代表行数的的数组只需要2个内存空间,
dp[2][N],
etc:
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < kk; j++)
{
for(int k = 0; k < kk; k++)
{
if(!judge(num[j], num[k]))
continue;
int tep = shu(i, num[j]);
dp[v^1][num[j]] = max(dp[v^1][num[j]], dp[v][num[k]] + tep);
}
}
v ^= 1;//在这层循环中异或
}
5,初始化,(多数为)第一行,假设输入数据只有一行时,如何输出,这样好想。
6,dp[i][state]当数据仅与上一行有关时,二维数组,第i行状态为state时的最优解。当数据与上两行有关时,dp[i][state'][state]
代表第i行,其为state状态,i-1行为state'状态。
7,特殊情况,有些问题的状态并不只有选择与不选两种状态,此时,需要用到三进制的状态压缩来转换。Etc:hdu3001。思路相仿,但由二进制变为三进制。
Tips:好用的小技巧
遍历i之前的所有状态
for(int i=1;i<(1<<a);i++){
for(int j=i;j>0;j=i&(j-1)){
if(ok[j])
dp[i]=min(dp[i],dp[i-j]+1);
}
}
/分割线
#include<iostream>
using namespace std;
int main()
{
int i;
for(i=1; i<=10; i++)
cout<<(i&(-i))<<endl;
return 0;
}
返回 i 的二进制数最低位为1的权值
例如
10100最低位的1权值是4
//
2,TSP问题
0代表没去,1代表已去。
部分题目(有多条线路前往目标点)需要弗洛伊德优化
模板:
for(i=0;i<=n;i++){
for(j=0;j<=n;j++){
for(k=0;k<=n;k++)
map[i][j]=min(map[i][j],map[i][k]+map[k][j]);///弗洛伊德优化
}
}
状态转移方程:dp[state][i] =min{dp[state][i],dp[state'][j]+dis[j][i]} 到i点时state状态的最短距离dis用弗洛伊德优化求出。
二,数位DP
主要是在区间内对符合条件数的统计,判断条件多为与上一位数的关系。有重复性。
下面是个记忆化搜索dfs的模板,以hdu2089为例。
len为当前位置,从高向低dp
state代表状态,即上一位是否满足条件
fp为边线,以此来确定是否为最高位
int dfs(int len,bool state,bool fp){
if(!len)//dp结束,返回
return 1;
if(!fp&&dp[len][state]!=-1)//不是边界且有意义
return dp[len][state];
int res=0;int fpmax=fp?d[len]:9;
for(int i=0;i<=fpmax;i++){
if(i==4||state&&i==2)continue;//此处即为判断条件
res+=dfs(len-1,i==6,fp&&i==fpmax);
}
if(!fp)
dp[len][state]=res;
return res;
}
主要是要学会将问题转换为树的形式,这方面还有欠缺,具体资料,可参考刘聪的《浅谈数位类统计问题 》。其中的思路明确。
这方面相对弱,要多看。。。一开始看了个难题,然后没看下去。。。。有漏洞
三,树形DP,上次有总结,在此按下不表。
就目前来说,只是对DP的大体情况有所了解,知晓模板,但手生,接下来再多看点代码,就该真正完全不能看题解,自己A题了。。。。。。TAT。
当前问题在于
1,热情一阵一阵的,缺少持续的动力。
2,没有写博客的习惯,今后要多看多总结。
3,做题时,一定要忍住,不看题解啊。。。。。。。。。。。。。。。。。。
4,看代码时一定要钻进去,将一个问题彻底搞懂,<和<=也要搞明白,不然,一步错,步步错。
ACM难,比想象的难很多,期望我能成为叉姐说的那种“CPU中等,内存没有,但是硬盘比较大的类型”的人。作为其他方面不行的选手来说,最好的做法就是提高自己的硬盘容量。
前路漫漫,共勉吧。