博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态规划(冬令营课堂笔记)
阅读量:4948 次
发布时间:2019-06-11

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

 

  

  

  

  

  

  

简单问题

01背包

一个容量为m的背包,有n个物品,第i个物品的体积为wi,价值为ci。选择若干物品,使得体积总和不超过m的情况下价值总和最大。

n<=100,m<=10000。

 

搜索  复杂度为2^n

void dfs(int x,int y,int z)//当前物品编号,当前容量,当前价值{    if(x==n+1)    {        if(y

如果前两维相同,只需选择第三维的最大值

小小的变形

const int INF=0x7f;int dfs(int x,int y){    int ans;    if(x==n+1)    {        if(y>m)return -INF;        return 0;    }    ans=max(dfs(x+1,y+w[x])+c[x],dfs(x+1,y));    return ans;}dfs(1,0);

加一个数组记录

const int INF=0x7f;int dfs(int x,int y){    if(x==n+1)    {        if(y>m)return -INF;        return 0;    }    dp[x][y]=max(dfs(x+1,y+w[x])+c[x],dfs(x+1,y));    return dp[x][y];}dfs(1,0);

应用记录状态  记忆化搜索 n*m

const int INF=0x7f;int dfs(int x,int y){    if(y>m)return -INF;    if(x==n+1)    {        return 0;    }    if(dp[x+1][y+w[x]])             //选该物品     dp[x][y]=max(dp[x+1][y+w[x]]+c[x],dp[x][y]);    else    dp[x][y]=max(dfs(x+1,y+w[x])+c[x],dp[x][y]);         if(dp[x+1][y])             //不选该物品     dp[x][y]=max(dp[x+1][y]+c[x],dp[x][y]);    else    dp[x][y]=max(dfs(x+1,y))+c[x],dp[x][y]);         return dp[x][y];}dfs(1,0);

递归变递推

先写出搜索

最大/最小值 存放到数组中

后面递归该状态时 直接使用数组中的值来代替

O(dfs里的状态个数*转移的时间复杂度)

 

找边界

找递推方法(顺序还是逆序)

转移(推转移方程)

搜索->记忆化搜索->递归变递推

for(int i=n;i>=1;i--)     for(int j=0;j<=m;j++)         dp[i][j]=max(dp[i+1][j],dp[i+1][j+w[i]]+c[i]);ans=dp[1][0]

012背包

一个容量为m的背包,有n个物品,第i个物品的体积为wi,价值为ci,有2个。

选择若干物品,使得体积总和不超过m的情况下价值总和最大。

记忆化搜索

const int INF=0x7f;int dfs(int x,int y,int z){    if(x==n+1){
if(y

部分背包

一个容量为m的背包,有n个物品,第i个物品的体积为wi,价值为ci,有ki个。

选择若干物品,使得体积总和不超过m的情况下价值总和最大。

记忆化搜索

int dfs(int x,int y){    if (y>m) return -INF;    if (x==n+1) return 0;    for (int i=0; i<=k[x]; i++)    {        if (dp[x+1][y+i*w[x]])            dp[x][y]=max(dp[x][y],dp[x+1][y+i*w[x]]+c[x]);        else              dp[x][y]=max(dp[x][y],dfs(x+1,y+i*w[x])+i*c[x]);    }    return dp[x][y];}dfs(1,0);

递推

for (i=n; i>=1; i--)    for (j=0; j<=m; j++)    for (l=0; l<=k[i]; l++)    dp[i][j]=max(dp[i][j],dp[i+1][j+l*w[i]]+l*c[i]);dp[1][0]

机器分配

有n家店,每家店都有m台机器,第i家店购买j台机器花费a[i][j]元(可能存在a[i][j]>a[i][j+1]),要购买总共m台机器,求最小花费。

搜索

//机器分配 dfs(int x,int y,int z){    if(y>m)return;    if(x==n+1)    {        if(y==n+1)ans=min(ans,z);        return;    }    for(int i=0;i<=m;i++)        dfs(x+1;y+i,z+a[x][i]);}dfs(1,0,0);

小小的变形

//机器分配 int dfs(int x,int y){    if(y>m)return -INF;    if(x==n+1)    {        if(y==m)return 0;//再也不需要买机器         return -INF;    }    for(int i=0;i<=m;i++)    dp[x][y]=min(dp[x][y],dfs(x+1,y+i)+a[x][i]);    return dp[x][y];}dfs(1,0);

记忆化搜索

//机器分配 int dfs(int x,int y){    if(y>m)return -INF;    if(x==n+1)    {        if(y==m)return 0;//再也不需要买机器         return -INF;    }    for(int i=0;i<=m;i++)    if(dp[x+1][y+i])    dp[x][y]=min(dp[x][y],dp[x+1][y+i]+a[x][i]);    else    dp[x][y]=min(dp[x][y],dfs(x+1,y+i)+a[x][i]);    return dp[x][y];}dfs(1,0);

递推

for(int i=n;i>=1;i--)    for(int j=0;j<=m;j++)    {        dp[i][j]=INF;        for(k=0;k<=m-j;k++)        dp[i][j]=min(dp[i][j],dp[i+1][j+k]+a[i][k]);    }ans=dp[1][0]

烽火传递

给定n个非负整数,选择其中若干数字,使得每连续k个数中至少有一个数被选出。

要求选择的数字之和尽可能小。

搜索

void dfs(int x,int y){    if(x==n+1){ans=min(ans,y);return;}    for(int i=x+1;i<=min(n+1,x+k);i++)        dfs(i,y+a[i]);//i是下一个 }dfs(0,0);

记忆化

int dfs(int x){    if(x==n+1)return 0;    dp[x]=INF;    for(int i=x+1;i<=min(n+1,x+k);i++)    if(dp[i])dp[x]=min(dp[x],dp[i]+a[i]);    else    dp[x]=min(dp[x],dfs(i)+a[i]);    return dp[x];}dfs(0);

递推

/*dp[n+1]=0;dp[1]  dp[2] dp[3] .. dp[1+k]*/for (i=n; i>=0; i--){    dp[i]=INF;    for (int j=i+1; j<=min(n+1,i+k); j++)        dp[i]=min(dp[i],dp[j]+a[j]);}dp[0]

花店橱窗问题

给定一个n*m的矩阵A(n<=m),求一个序列a1,a2,…,an满足1<=a1<a2<…<an<=m。使得A[1][a1]+A[2][a2]+…+A[n][an]最大。A可能有负数。

搜索

void dfs(int x,int y,int z){    if(x==n+1)    {        if(y==m+1)ans=max(ans,z);        return;    }    for(int i=y+1;i<=m;i++)    dfs(x+1,i,z+a[x+1][i]);}dfs(0,0,0);

记忆化搜索

int dfs(int x,int y){    if(x==n+1)    {        if(y==m+1)return 0;        else return -INF;    }    for(int i=y+1;i<=m;i++)    {        if(dp[x+1][i])        dp[x][y]=max(dp[x][y],dp[x+1][i]+a[x+1][i]);        else        dp[x][y]=max(dp[x][y],dfs(x+1,i)+a[x+1][i]);        return dp[x][y];    }}dfs(0,0);

递推

/*dp[n+1][m+1]=0; dp[n+1][0~m]=-INF;dp[1][]  dp[2][] dp[3][]*/for (i=n; i>=0;i--)    for (j=0; j<=m+1; j++)    for (k=j+1; k<=m+1; k++)    dp[i][j]=max(dp[i][j],dp[i+1][k]+a[i+1][k]);cout<

 

转载于:https://www.cnblogs.com/thmyl/p/6339339.html

你可能感兴趣的文章
Linux文件权限
查看>>
機械の総合病院 [MISSION LEVEL: C]
查看>>
Delphi通用的序列化代码
查看>>
Educational Codeforces Round 6 D. Professor GukiZ and Two Arrays 二分
查看>>
设计模式:职责链模式(Chain Of Responsibility)
查看>>
stm32f429i disc usb cdc vcp 虚拟串口 example project (CubeMX Hal)
查看>>
Robust PCA via Outlier Pursuit
查看>>
实战练习细节(分行/拼接字符串/字符串转int/weak和copy)
查看>>
wddm 部署问题解决
查看>>
Strict Standards: Only variables should be passed by reference
查看>>
Slab-based Intersection
查看>>
将输入流转为字符串工具类
查看>>
hiho_offer收割18_题解报告_差第四题
查看>>
高斯消元
查看>>
AngularJs表单验证
查看>>
regasm.exe 注册dll
查看>>
什么是死锁,简述死锁发生的四个必要条件,如何避免与预防死锁
查看>>
静态方法是否属于线程安全
查看>>
fegin 调用源码分析
查看>>
Linux的基本命令
查看>>