• 区间DP


    主要由例题引入

    重点: 最优子结构,可划分成部分(有点像分治)

    1. luogu P1220 关路灯

     1 ## 区间DP:luogu :P1220
     2 
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<algorithm>
     6 #define MAX 555
     7 int n,c;
     8 int dp[MAX][MAX][2];
     9 //dp[i][j][0/1]表示老张关完i ~~ j的灯时所在的位置
    10 int sum[MAX]/*前缀和:用来计算功率*/,a[MAX],b[MAX];/*a是位置,b是功率*/ 
    11 
    12 int min(int a, int b) {
    13     return a >= b ? b : a;//提高效率 
    14 }
    15 
    16 
    17 int main() {
    18     scanf("%d%d",&n,&c);
    19     memset(dp,88,sizeof(dp)); 
    20     for(int i = 1; i <= n; i++) {
    21         scanf("%d%d",&a[i],&b[i]);
    22         sum[i] =sum[i - 1] + b[i];
    23     }
    24 //    printf("%d",sum[2]);
    25     dp[c][c][0] = dp[c][c][1] = 0;//老张直接将自己所在的灯关掉,无时间,所以无功
    26     for(int l = 2; l <= n; l++) {// 枚举现在的灯 
    27         for(int i = 1; i + l - 1 <= n; i++) {  //不能越界          
    28             int j = i + l - 1;//                     时间∨
    29             dp[i][j][0] = min(dp[i + 1][j][0] + (a[i + 1] - a[i]) * (sum[n] - sum[j] + sum[i]),//包括了i这一点的电能,因为走过来的过程中灯i也会耗电
    30                         dp[i + 1][j][1] + (a[j] - a[i]) * (sum[n] - sum[j] + sum[i])) ;
    31             dp[i][j][1] = min(dp[i][j - 1][1] + (a[j] - a[j - 1]) * (sum[n] - sum[j - 1] + sum[i - 1]),//已经关了[i,j - 1] 注意:i关了,j还没关 所以j会耗电,i不会 
    32                         dp[i][j - 1][0] + (a[j] - a[i]) * (sum[n] - sum[j - 1] + sum[i - 1]));
    33         
    34         //dp[i][j][0] ---- i + 1    dp[i][j][1] ---- j - 1 他们对应的都是上一个状态 
    35         }
    36     } 
    37     int ans = min(dp[1][n][0] , dp[1][n][1]);
    38     printf("%d",ans);
    39 }

     2. luogu P1880 [NOI1995]石子合并

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 #define MAXN 200+9
     5 #define INF 2147000047
     6 
     7 int fmax[MAXN][MAXN], fmin[MAXN][MAXN],sum[MAXN];
     8 int lenth,n,ans1,ans2,a[MAXN];
     9 
    10 void init() {//将1~n的圈改成1~2n链 
    11     scanf("%d",&n);
    12     lenth = n*2;
    13     for(int i = 1; i <= n; i++) scanf("%d",&a[i]), a[i+n] = a[i];
    14     for(int i = 1; i <= lenth; i++) {
    15         sum[i] = sum[i-1] + a[i];
    16         fmax[i][i] = 0; fmin[i][i] = 0;//初始化边界 
    17     }    
    18 }
    19 
    20 void dp() {
    21     for(int L = 2; L <= n; L++) //以合并的堆数为阶段(大堆由小堆决定 
    22         for(int i = 1; i <= lenth-L+1; i++) { //合并的起始位置
    23             int j = i+L-1;//计算出合并的结束位置 
    24             fmax[i][j] = 0, fmin[i][j] = INF;
    25             for(int k = i; k < j; k++) { // 决策 (因为后面有k+1,所以k要<j 
    26                 fmax[i][j] = max(fmax[i][j], fmax[i][k]+fmax[k+1][j]+(sum[j]-sum[i-1]));
    27                 fmin[i][j] = min(fmin[i][j], fmin[i][k]+fmin[k+1][j]+(sum[j]-sum[i-1]));
    28                 //这的“(sum[j]-sum[i-1])” 也可以加在for(k)的外面 
    29             }
    30         }
    31     
    32     ans1 = 0, ans2 = INF;
    33     for(int i = 1; i <= n; i++) {//以DP起点位置判断出最值 
    34         ans1 = max(ans1, fmax[i][i+n-1]);
    35         ans2 = min(ans2, fmin[i][i+n-1]);
    36     }
    37 }
    38 
    39 int main() {
    40     init();
    41     dp();
    42     printf("%d
    %d
    ",ans2, ans1);
    43 }

    3. luogu P1063 能量项链(最优矩阵链乘

     1 /*ps: 不是贪心哦*/
     2 #include<cstdio>
     3 #include<algorithm>
     4 using namespace std;
     5 #define MAXN 200+99
     6 
     7 int n,lenth,ans;
     8 int f[MAXN][MAXN], head[MAXN], tail[MAXN]; 
     9 
    10 int main() {
    11     scanf("%d",&n);
    12     for(int i = 1; i <= n; i++) scanf("%d",&head[i]), head[i+n] = head[i]; 
    13     lenth = n*2; //仍然换成链状
    14     for(int i = 1; i <= lenth-1; i++) tail[i] = head[i+1];//(注意这还要"-1",因为将1和2n合并的话,只需将1和n合并(下面一样 
    15     tail[lenth] = head[1];
    16 //    for(int i = 1; i <= lenth-1; i++) f[i][i] = 0;//初始化边界  
    17     for(int L = 1; L <= n-1; L++) //以合并次数为阶段(次数从1开始 
    18         for(int i = 1; i <= lenth-L; i++) {//以起始位置为状态 
    19             int j = i+L;//算出结束位置(包括第j个 
    20             for(int k = i; k < j; k++) {//k 仍然<j 
    21                 f[i][j] = max(f[i][j], f[i][k] + f[k+1][j] + head[i]*tail[k]*tail[j]); //决策 
    22             }
    23         }
    24     
    25     for(int i = 1; i <= n; i++) ans = max(ans, f[i][i+n-1]);//以起点求出最值
    26     printf("%d",ans); 
    27 }

    4. 最优三角剖分(LOJ#10149.凸多边形的划分(不一样的出现啦

  • 相关阅读:
    快速幂
    1112个人赛,最长回文串常见算法讨论
    11-05-sdust-个人赛赛后随想
    UVA 1149 Bin Packing
    UVa 1608,Non-boring sequences
    UVa 10954,Add All
    UVa 714,Copying Books
    Careercup
    Careercup
    Careercup
  • 原文地址:https://www.cnblogs.com/tyner/p/10804608.html
Copyright © 2020-2023  润新知