• 区间DP及其拓展


    石子合并

    282. 石子合并 - AcWing题库https://www.acwing.com/problem/content/284/

    环形石子合并 

    题目 环形石子合并 

    1. #include
    2. using namespace std;
    3. const int N=410,INF=0x3f3f3f3f;
    4. int f[N][N];
    5. int g[N][N];
    6. int a[N];
    7. int s[N];
    8. int main()
    9. {
    10. int n;
    11. cin>>n;
    12. memset(f,INF,sizeof f);
    13. memset(g,-INF,sizeof g);
    14. for(int i=1;i<=n;i++)
    15. {
    16. cin>>a[i];
    17. a[i+n]=a[i];
    18. }
    19. for(int i=1;i<=n*2;i++)
    20. {
    21. s[i]=a[i]+s[i-1];
    22. f[i][i]=0;
    23. g[i][i]=0;
    24. }
    25. for(int len=2;len<=n;len++)
    26. for(int i=1;i+len-1<=n*2;i++)
    27. {
    28. int l=i,r=len+i-1;
    29. for(int k=l;k
    30. {
    31. f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
    32. g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]+s[r]-s[l-1]);
    33. }
    34. }
    35. int minv=INF,maxv=-INF;
    36. for(int i=1;i<=n;i++)
    37. {
    38. minv=min(minv,f[i][i+n-1]);
    39. maxv=max(maxv,g[i][i+n-1]);
    40. }
    41. cout<
    42. }

    能量项链【区间DP】 

     题目 能量项链https://www.acwing.com/problem/content/description/322/

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N=210;
    5. ll f[N][N];
    6. ll a[N];
    7. int main()
    8. {
    9. int n;
    10. cin>>n;
    11. for(int i=1;i<=n;i++)
    12. {
    13. cin>>a[i];
    14. a[i+n]=a[i];
    15. }
    16. for(int len=3;len<=n+1;len++)
    17. for(int l=1;len+l-1<=2*n;l++)
    18. {
    19. int r=l+len-1;
    20. for(int k=l+1;k
    21. f[l][r]=max(f[l][r],f[l][k]+f[k][r]+a[l]*a[k]*a[r]);
    22. }
    23. ll res=0;
    24. for(int i=1;i<=n;i++)
    25. res=max(res,f[i][i+n]);
    26. cout<
    27. }

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N=35;
    5. int w[N],f[N][N],g[N][N];//f记录[l,r]区间的分数,g记录[l,r]的根节点
    6. void dfs(int l,int r)//前序遍历是根左右
    7. {
    8. if(l>r) return ;
    9. int root=g[l][r];//根
    10. cout<' ';
    11. dfs(l,root-1);//左子树
    12. dfs(root+1,r);//右子树
    13. }
    14. int main()
    15. {
    16. int n;
    17. cin>>n;
    18. for(int i=1;i<=n;i++) cin>>w[i];
    19. memset(f,-0x3f,sizeof f); //因为要求最大值,则初始化为负无穷
    20. for(int len=1;len<=n;len++) //枚举[l,r]的长度
    21. for(int l=1;l+len-1<=n;l++)//枚举l
    22. {
    23. int r=l+len-1;
    24. if(len==1) //假如只有自己,则分数是自己,根也是自己
    25. {
    26. f[l][r]=w[l];
    27. g[l][r]=l;
    28. }
    29. else
    30. {
    31. for(int k=l;k<=r;k++)//枚举[l,r]之间的根节点
    32. {
    33. int left = k==l ? 1 : f[l][k-1];//假如k是等于l,说明l到k没有左子树,则分数为1
    34. int right = k==r ? 1 : f[k+1][r];//假如k是等于r,说明l到k没有右子树,则分数为1
    35. int socre=left*right+w[k];//算一下分数
    36. if(f[l][r]//假如可以更新最大值
    37. {
    38. f[l][r]=score;
    39. g[l][r]=k;
    40. }//更新分数,还有[l,r]的根节点k
    41. }
    42. }
    43. }
    44. cout<1][n]<//输出[l,r]区间的二叉树的分数
    45. dfs(1,n);//前序遍历求根节点
    46. return 0;
    47. }

     凸多边形的划分【区间DP+高精度=缝合怪】 

     由于这题每个w[i]都是10^9,则三个乘以的话就10^27,则要自己写个高精度加法与乘法

    1. //没加高精度的模板,过不了
    2. #include
    3. using namespace std;
    4. const int N=210;
    5. int w[N],f[N][N];
    6. int main()
    7. {
    8. int n;
    9. cin>>n;
    10. for(int i=1;i<=n;i++) cin>>w[i];
    11. for(int len=3;len<=n;len++)//枚举l到r的长度
    12. for(int l=1;l+len-1<=n;l++)
    13. {
    14. int r=len+l-1;
    15. f[l][r]=0x3f3f3f3f;//因为要求最小值,所以初始化为正无穷
    16. for(int k=l+1;k
    17. f[l][r]=min(f[l][r],f[l][k]+f[k][r]+w[l]*w[k]*w[r]);
    18. }
    19. cout<1][n]<
    20. return 0;
    21. }

    高精度 优化

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N=55,M=35;
    5. ll w[N],f[N][N][M];
    6. void add(ll a[],ll b[])//高精度加法
    7. {
    8. static ll c[M];
    9. memset(c,0,sizeof c);
    10. ll t=0;
    11. for(int i=0;i
    12. {
    13. t+=a[i]+b[i];
    14. c[i]=t%10;
    15. t/=10;
    16. }
    17. memcpy(a,c,sizeof c);
    18. }
    19. void mul(ll a[],ll b)//高精度乘法
    20. {
    21. static ll c[M];
    22. memset(c,0,sizeof c);
    23. ll t=0;
    24. for(int i=0;i
    25. {
    26. t+=a[i]*b;
    27. c[i]=t%10;
    28. t/=10;
    29. }
    30. memcpy(a,c,sizeof c);
    31. }
    32. bool cmp(ll a[],ll b[])//比较两个数的大小
    33. {
    34. for(int i=M-1;i>=0;i--)
    35. if(a[i]>b[i]) return true;
    36. else if(a[i]return false;
    37. return false;
    38. }
    39. void print(ll a[])//用来输出答案
    40. {
    41. int k=M-1;
    42. while(k&&!a[k]) k--;
    43. while(k>=0) cout<
    44. cout<
    45. }
    46. int main()
    47. {
    48. int n;
    49. cin>>n;
    50. for(int i=1;i<=n;i++) cin>>w[i];
    51. ll temp[M];
    52. for(int len=3;len<=n;len++)//枚举l到r的长度
    53. for(int l=1;l+len-1<=n;l++)
    54. {
    55. int r=len+l-1;
    56. //f[l][r]=0x3f3f3f3f;
    57. f[l][r][M-1]=1;//因为要求最小值,所以初始化为正无穷,最高位是1,说明1e34,已经很大了
    58. for(int k=l+1;k
    59. {
    60. // f[l][r]=min(f[l][r],f[l][k]+f[k][r]+w[l]*w[k]*w[r]);
    61. memset(temp,0,sizeof temp);//清空上一次的数组
    62. temp[0]=w[l];
    63. mul(temp,w[k]);
    64. mul(temp,w[r]);
    65. add(temp,f[l][k]);
    66. add(temp,f[k][r]);
    67. if(cmp(f[l][r],temp))
    68. memcpy(f[l][r],temp,sizeof temp);
    69. }
    70. }
    71. print(f[1][n]);
    72. return 0;
    73. }

    加分二叉树 

    题目 icon-default.png?t=N3I4http://ybt.ssoier.cn:8088/problem_show.php?pid=1833

     

     

    1. #include
    2. using namespace std;
    3. const int N=35;
    4. int f[N][N],g[N][N];
    5. int w[N];
    6. int n;
    7. void dfs(int l,int r)
    8. {
    9. if(l>r)return;
    10. int root=g[l][r];
    11. cout<" ";
    12. dfs(l,root-1);
    13. dfs(root+1,r);
    14. }
    15. int main()
    16. {
    17. cin>>n;
    18. for(int i=1;i<=n;i++)
    19. cin>>w[i];
    20. for(int len=1;len<=n;len++)
    21. for(int l=1;l+len-1<=n;l++)
    22. {
    23. int r=l+len-1;
    24. if(len==1)
    25. {
    26. f[l][r]=w[l];
    27. g[l][r]=l;
    28. }
    29. else
    30. {
    31. for(int k=l;k<=r;k++)
    32. {
    33. int left = k==l ? 1 : f[l][k-1];
    34. int right = k==r ? 1 :f[k+1][r];
    35. int sorce = w[k] + left * right;
    36. if(f[l][r]
    37. {
    38. f[l][r]=sorce;
    39. g[l][r]=k;
    40. }
    41. }
    42. }
    43. }
    44. cout<1][n]<
    45. dfs(1,n);
    46. }

     

    棋盘分割 

    题目 棋盘分割https://www.acwing.com/problem/content/description/323/

    解析 https://www.acwing.com/solution/content/62836/

    横着切: 

     竖着切:

    1. #include
    2. using namespace std;
    3. const int N=15,M=9;
    4. const double INF=1e9;
    5. int s[M][M];//二维前缀和
    6. double f[M][M][M][M][N];
    7. double X;//平均数
    8. int n;
    9. double get(int x1,int y1,int x2,int y2)//求子矩阵的方差
    10. {
    11. double sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]-X;//求方差
    12. return sum*sum/n;
    13. }
    14. double dp(int x1,int y1,int x2,int y2,int k)//记忆化搜索
    15. {
    16. double &v=f[x1][y1][x2][y2][k];
    17. if(v>=0) return v;//假如已经处理过直接返回他的值
    18. if(k==1) return v=get(x1,y1,x2,y2);//假如切割是一次,则就是最后一块子矩阵,则直接求他的值,不用再切割
    19. v=INF;//因为要求最小值,初始化为正无穷
    20. for(int i=x1;i//枚举横向切割
    21. {
    22. v=min(v,dp(x1,y1,i,y2,k-1)+get(i+1,y1,x2,y2));//取上面的部分
    23. v=min(v,dp(i+1,y1,x2,y2,k-1)+get(x1,y1,i,y2));//取下面的部分
    24. }
    25. for(int i=y1;i//枚举纵向切割
    26. {
    27. v=min(v,dp(x1,y1,x2,i,k-1)+get(x1,i+1,x2,y2));//取左边部分
    28. v=min(v,dp(x1,i+1,x2,y2,k-1)+get(x1,y1,x2,i));//取右边部分
    29. }
    30. return v;
    31. }
    32. int main()
    33. {
    34. cin>>n;
    35. for(int i=1;i<=8;i++)
    36. for(int j=1;j<=8;j++)
    37. {
    38. cin>>s[i][j];
    39. s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];//二维前缀和
    40. }
    41. memset(f,-1,sizeof f);//初始化为-1,便于记忆化搜索
    42. X=(double)s[8][8]/n;//求平均数
    43. printf("%.3lf\n",sqrt(dp(1,1,8,8,n)));//输出根号方差,即均方差
    44. return 0;
    45. }

  • 相关阅读:
    解读《超越智商》
    疑惑与解答
    开快递驿站能赚钱么?去掉成本,一个月能赚多少钱?
    Python+Requests+Pytest+YAML+Allure实现接口自动化
    rust输入输出
    基于JAVA评标专家管理信息系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    webRTC H265浏览器播放器+metaRTC推流实现webRTC H265解决方案
    CEF内核浏览器安装、解决过滤图片、链接弹窗问题
    codeforces每日5题(均1500)-第二十一天
    double 和 float 的区别
  • 原文地址:https://blog.csdn.net/m0_64378422/article/details/127817486