Greedy Pie Eaters(区间DP板子)

题目描述

Farmer John has M cows, conveniently labeled 1…M, who enjoy the occasional change of pace from eating grass. As a treat for the cows, Farmer John has baked N pies (1≤N≤300), labeled 1…N. Cow i enjoys pies with labels in the range [li,ri] (from li to ri inclusive), and no two cows enjoy the exact same range of pies. Cow i also has a weight, wi, which is an integer in the range 1…106.
Farmer John may choose a sequence of cows c1,c2,…,cK, after which the selected cows will take turns eating in that order. Unfortunately, the cows don't know how to share! When it is cow ci's turn to eat, she will consume all of the pies that she enjoys --- that is, all remaining pies in the interval [lci,rci]. Farmer John would like to avoid the awkward situation occurring when it is a cows turn to eat but all of the pies she enjoys have already been consumed. Therefore, he wants you to compute the largest possible total weight (wc1+wc2+…+wcK) of a sequence c1,c2,…,cK for which each cow in the sequence eats at least one pie.

SCORING:
Test cases 2-5 satisfy N≤50 and M≤20.
Test cases 6-9 satisfy N≤50.

输入

The first line contains two integers N and M (1≤M≤N(N+1)/2).
The next M lines each describe a cow in terms of the integers wi,li, and ri.

输出

Print the maximum possible total weight of a valid sequence.

样例输入 Copy

2 2
100 1 2
100 1 1

样例输出 Copy

200

提示

In this example, if cow 1 eats first, then there will be nothing left for cow 2 to eat. However, if cow 2 eats first, then cow 1 will be satisfied by eating the second pie only.

区间dp的基础知识
定义 :区间dp就是在区间上进行动态规划,求解一段区间上的最优解。主要是通过合并小区间的 最优解进而得出整个大区间上最优解的dp算法。
最基础的伪代码
 1 //mst(dp,0) 初始化DP数组
 2 for(int i=1;i<=n;i++)
 3 {
 4     dp[i][i]=初始值
 5 }
 6 for(int len=2;len<=n;len++)  //区间长度
 7 for(int i=1;i<=n;i++)        //枚举起点
 8 {
 9     int j=i+len-1;           //区间终点
10     if(j>n) break;           //越界结束
11     for(int k=i;k<j;k++)     //枚举分割点,构造状态转移方程
12     {
13         dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
14     }
15 }
16 
17 原文链接:https://blog.csdn.net/my_sunshine26/article/details/77141398
平行四边形优化
用s[i][j]表示区间[i,j]中的最优分割点,那么第三重循环可以从[i,j-1)优化到【s[i][j-1],s[i+1][j]】。(这个时候小区间s[i][j-1]和s[i+1][j]的值已经求出来了,然后通过这个循环又可以得到s[i][j]的值)
 1 mst(dp,0x3f);
 2         for(int i=1;i<=n;i++)
 3         {
 4             scanf("%d",&x);
 5             sum[i]=sum[i-1]+x;
 6             dp[i][i]=0;
 7             s[i][i]=i;
 8         }
 9         for(int len=2;len<=n;len++)
10         for(int i=1;i<=n;i++)
11         {
12             int j=i+len-1;
13             if(j>n) continue;
14             for(int k=s[i][j-1];k<=s[i+1][j];k++)
15             {
16                 if(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]<dp[i][j])
17                 {
18                     dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
19                     s[i][j]=k;
20                 }
21             }
22         }
23         printf("%d\n",dp[1][n]);
View Code

 

本题AC代码

#include<bits/stdc++.h>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
const int N=310;
int dp[N][N],w[N][N][N],f[N][N];
int n,m;
 
void DP()
{
        for(int i=1;i<=n;i++){
        for(int j=i;j>=1;j--){
            //for(int k=i,k<=j-1;k++)f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
            for(int k=i;k<=n;k++){
                if(j>1)
                    w[i][j-1][k]=max(w[i][j-1][k],w[i][j][k]);
                if(k<n)
                   w[i][j][k+1]=max(w[i][j][k+1],w[i][j][k]);
            }
        }
    }
      for(int i=n;i>=1;i--){
        for(int j=i;j<=n;j++){
            for(int k=i;k<=j-1;k++)dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
            for(int k=i;k<=j;k++) dp[i][j]=max(dp[i][j],w[k][i][j]+(k>i?dp[i][k-1]:0)+(k<j?dp[k+1][j]:0));
        }
    }
 
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int ww,l,r;
        scanf("%d%d%d",&ww,&l,&r);
        for(int j=l;j<=r;j++)
            w[j][l][r]=max(ww,w[j][l][r]);
    }
    DP();
    printf("%d\n",dp[1][n]);
    return 0;
}

 

posted @ 2020-02-02 10:44  sylvia11  阅读(250)  评论(0编辑  收藏  举报