5月16日总结

背包总结

01背包问题:N个物品,每个物品只有1件,每个物品价值为Vi,体积为Wi,容量为M的背包最多装多少价值的物品。

d p [ i ] 表 示 容 量 为 i 时 , 最 多 装 多 少 价 值 dp[i]表示容量为i时,最多装多少价值 dp[i]i
f o r       i ( 1 , n ) for\ \ \ \ \ i(1,n) for     i(1,n)
f o r       j ( V , w [ i ] ) for\ \ \ \ \ j(V,w[i]) for     j(V,w[i])
d p [ j ] = m a x ( d p [ j ] , d p [ j − w [ i ] ] + v [ i ] ) dp[j]=max(dp[j],dp[j-w[i]]+v[i]) dp[j]=max(dp[j],dp[jw[i]]+v[i])


第 二 层 循 环 必 须 从 V 到 w [ i ] : 每 个 物 品 只 有 一 件 , 不 会 导 致 同 一 件 物 品 多 次 使 用 第二层循环必须从V到w[i]:每个物品只有一件,不会导致同一件物品多次使用 Vw[i]:使


如 果 循 环 从 w [ i ] 到 V , 则 当 j = 2 ∗ w [ i ] 时 如果循环从w[i]到V,则当j=2*w[i]时 w[i]V,j=2w[i]
d p [ j − w [ i ] ] = v [ i ] , d p [ j ] = d p [ j − w [ i ] ] + v [ i ] = 2 ∗ v [ i ] , 放 了 2 次 dp[j-w[i]]=v[i],dp[j]=dp[j-w[i]]+v[i]=2*v[i],放了2次 dp[jw[i]]=v[i],dp[j]=dp[jw[i]]+v[i]=2v[i],2
当 j 远 大 于 w [ i ] 时 , 第 i 件 物 品 会 被 多 次 使 用 , 变 成 完 全 背 包 问 题 当j远大于w[i]时,第i件物品会被多次使用,变成完全背包问题 jw[i]i使
所 以 , 01 背 包 和 完 全 背 包 的 一 维 D P , 第 二 层 循 环 方 向 相 反 所以,01背包和完全背包的一维DP,第二层循环方向相反 01DP


如 果 初 始 化 d p [ 0 ] = 0 , d p [ 1... j ] = − i n f 如果初始化dp[0]=0,dp[1 ... j]=-inf dp[0]=0,dp[1...j]=inf
则 d p [ i ] 是 恰 好 容 量 为 i 时 的 背 包 最 大 价 值 , 如 果 不 能 恰 好 装 满 , 就 是 负 数 则dp[i]是恰好容量为i时的背包最大价值,如果不能恰好装满,就是负数 dp[i]i
因 为 当 容 量 溢 出 时 , d p [ j − w [ i ] ] 为 负 数 , 就 像 是 搭 建 空 中 楼 阁 , 因为当容量溢出时,dp[j-w[i]]为负数,就像是搭建空中楼阁, dp[jw[i]]
只 能 在 之 前 已 有 的 基 础 上 更 新 数 据 , 否 则 数 据 无 效 只能在之前已有的基础上更新数据,否则数据无效

完全背包:N个物品,每个物品有无数件,每个物品价值为Vi,体积为Wi,容量为M的背包最多装多少价值的物品。

f o r       i ( 1 , n ) for\ \ \ \ \ i(1,n) for     i(1,n)
f o r       j ( w [ i ] , V ) for\ \ \ \ \ j(w[i],V) for     j(w[i],V)
d p [ j ] = m a x ( d p [ j ] , d p [ j − w [ i ] ] + v [ i ] ) dp[j]=max(dp[j],dp[j-w[i]]+v[i]) dp[j]=max(dp[j],dp[jw[i]]+v[i])

多重背包:N个物品,每个物品有Si件,每个物品价值为Vi,体积为Wi,容量为M的背包最多装多少价值的物品。

可拆成01背包
f o r       i ( 1 , n ) for\ \ \ \ \ i(1,n) for     i(1,n)
f o r       k ( 1 , s [ i ] ) for\ \ \ \ \ k(1,s[i]) for     k(1,s[i])
f o r       j ( V , w [ i ] ) for\ \ \ \ \ j(V,w[i]) for     j(V,w[i])
d p [ j ] = m a x ( d p [ j ] , d p [ j − w [ i ] ] + v [ i ] ) dp[j]=max(dp[j],dp[j-w[i]]+v[i]) dp[j]=max(dp[j],dp[jw[i]]+v[i])

二进制优化
for (int i = 1; i <= n; i++) {
     
    int num = min(p[i], V / w[i]);
    for (int k = 1; num > 0; k <<= 1) {
     
        if (k > num) k = num;
        num -= k;
        for (int j = V; j >= w[i] * k; j--)
            f[j] = max(f[j], f[j - w[i] * k] + v[i] * k);
    }

分组背包:N个物品,一共K组,每组有若干件,每组只能取一个,每个物品价值Vi,体积Wi,容量为M的背包最多装多少价值的物品。

f o r       p ( 1 , k ) / / k 组 for\ \ \ \ \ p(1,k)//k组 for     p(1,k)//k
f o r       j ( V , 0 ) for\ \ \ \ \ j(V,0) for     j(V,0)
f o r       i ( ) / / 组 内 物 品 个 数 for\ \ \ \ \ i()//组内物品个数 for     i()//
d p [ j ] = m a x ( d p [ j ] , d p [ j − w [ i ] ] + v [ i ] ) dp[j]=max(dp[j],dp[j-w[i]]+v[i]) dp[j]=max(dp[j],dp[jw[i]]+v[i])

状态压缩:当物品数N<=30,将长度为N的二进制串用0、1表示第i件物品取或不取。

对第i件物品,通过移位运算,与二进制状态相与, a & ( 1 < < i ) a\&(1<a&(1<<i),来确定该物品是否在该状态内

状态合并 a ∣ b a|b ab

集合差运算 a − b = a − a & b a-b=a-a\&b ab=aa&b

判断是否有交集 a & b a\&b a&b

状态 s s s的非空真子集 i i i
f o r ( i = s & ( s − 1 ) ; i ; i = s & ( i − 1 ) ) for(i=s\&(s-1);i;i=s\&(i-1)) for(i=s&(s1);i;i=s&(i1))

概率背包
如果每个事件都相互独立,那么通过将事件概率相乘,来表示多个事件发生的概率
类似

d p [ i ] = m a x ( d p [ i ] , d p [ i − w [ i ] ] ∗ p [ i ] ) dp[i]=max(dp[i],dp[i-w[i]]*p[i]) dp[i]=max(dp[i],dp[iw[i]]p[i])

随感

记得省赛就有个01背包的题,需要两维变量来描述,当时想到用一维01背包的套路,在特殊情况判断需要想明白怎么找到之前的状态,当时看榜找了三个签到题写了写,一个模拟竖式除法,一个垂直水平重力方向求方块最终组合形成的轮廓周长,再就是这个背包。
今天看了道01背包+旅行商的题,不是很好理解,昨天研究了第一问的背包问题,第二问是多旅行商问题,找了好多题解都没注释,自己按照理解写了写补充,这种不熟悉的题看懂了但不一定会用,算是扩展一下视野,长长见识了。
现在第十二周了,各种考试也快来了,什么破笔记也要收,烦得很,都是些应付的东西。算法设计考完试了,没复习,感觉很水,但我其他课都学得不怎么样,不复习就可能挂,哎,到头来还得突击,考个说得过去的成绩骗骗自己。其他科感觉支撑它的基础思想挺有意思,内容知识就很无聊,记这记那,讲得太死板。
最近感觉当码农真得不容易,不是我当初想的那样美好,脑力劳动与体力劳动双重施压,昨天舍友熬一宿,整的我没睡好,早上迷迷糊糊爬起来,吃完早饭赶到教室,接着昨天写的总结。现在身体还不错,但以后身体就不一定能吃得消。


想做自己,但又不完全是自己,人总是矛盾的。即使再执拗,也会向生活妥协。

int second(){
     
    int ed=(1<<n)-1;
    for(int i=1;i<=ed;i++)if(zz[i])                 //如果该状态一个裁判就能完成,必须从小到大,一点点合并加点
    for(int j=0;j<n;j++)if(i&(1<<j)){
                    //顺序无所谓,枚举状态内所有点
        for(int k=0;k<n;k++)if(!(i&(1<<k)))         //顺序无所谓,枚举状态外所有点
            dp[k][i|(1<<k)]=min(dp[k][i|(1<<k)],dp[j][i]+dis[j][k]);//加点
        //该状态一个裁判走所有点最后回到起点的最短耗时
        best[i]=min(best[i],dp[j][i]+dis[j][0]);//更新最优,每次都考虑并上到起点的距离,因为每个裁判都要回到起点
    }
    //多个裁判共同分担任务
    for(int i=2;i<=ed;i++)
        for(int j=i&(i-1);j;j=i&(j-1))//i的非空真子集
            best[i]=min(best[i],best[(i^j)|1]+best[j|1]);//由哪些集合合并能整体用时最少
            //i-j集合,j集合 并上起点,虽然best[1]=0,但还是要或上1,只需要其中一个或上1就行,否则状态缺失,为了理解方便,都或上1
    return best[ed];
}

你可能感兴趣的:(5月16日总结)