假期集训总结

来源:互联网 发布:大学生简历 知乎 编辑:程序博客网 时间:2024/04/28 05:15

                             假期训练总结

经过四个星期的训练,暑假集训也在此告一段落了。在此期间,进行了DP专题的学习,不得不说,进度太慢。一方面是由于专题本身的难度,另一方面则是我们知识的不足,还有缺少硬怼的精神。嘛,总之,吸取教训,今后改正,也是收获之一吧。下面对DP专题做一下简略的总结。

一,状压DP

目前已知题型:

1,图表类型问题

2TSP问题。

 

 

1,图表类型问题

etc:炮兵问题,放牛问题,矩阵问题,排兵布阵问题(状态多为两种:选与不选用01存储)

所求结果,最多可放置多少个;最多有几种放置方法;最大方格中所取数之和

主要模块

1,存图,map[i]|=(1<<j)或者map[i]+=1<<(j-1)其中存储的是不能放置的位置,即1为无法放置的,0为能

放置的。原因见2.

2,开个数组存储可进行选择的状态,1代表可选的,0代表不可选的。这样在与map&”时,取非即为可能的情况

011000都有可能,若条件11设为能放置,0为不能放置,这样可能漏掉00情况。

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,初始化,(多数为)第一行,假设输入数据只有一行时,如何输出,这样好想。

6dp[i][state]当数据仅与上一行有关时,二维数组,第i行状态为state时的最优解。当数据与上两行有关时,dp[i][state'][state]

代表第i行,其为state状态,i-1行为state'状态。

7,特殊情况,有些问题的状态并不只有选择与不选两种状态,此时,需要用到三进制的状态压缩来转换。Etchdu3001。思路相仿,但由二进制变为三进制。

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

 

//////////////////////////////////////////////////////////////////////////////////////////////////////

2TSP问题

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中等,内存没有,但是硬盘比较大的类型”的人。作为其他方面不行的选手来说,最好的做法就是提高自己的硬盘容量。

 

前路漫漫,共勉吧。

 

 

 

 

 

 

 

 

0 0