1. 程式人生 > 實用技巧 >飢餓的奶牛(題解)

飢餓的奶牛(題解)

這是一道很好的訓練dp的題,並且有很多細節需要注意 原題如下: 飢餓的奶牛

描述

牛在飼料槽前排好了隊。飼料槽依次用1到N(1N2000)編號。每天晚上,一頭幸運的牛根據約翰的規則,吃其中一些槽裡的飼料。

約翰提供N個區間的清單。一個區間是一對整數l,r(1lrN),表示一些連續的飼料槽,比如1-3,7-8,34等等。牛可以任意選擇區間,但是牛選擇的區間不能有重疊。

當然,牛希望自己能夠吃得越多越好。給出一些區間,幫助這隻牛找一些區間,使它能吃到最多的東西。

在上面的例子中,1-334是重疊的;聰明的牛選擇1378,這樣可以吃到5個槽裡的東西。

輸入

第一行,整數N(1N2000)。

2到N+1行,每行兩個整數,表示一個區間,較小的端點在前面。

輸出

僅一個整數,表示最多能吃到多少個槽裡的食物。

輸入樣例 1

3
1 3
7 8
3 4

輸出樣例 1

5
看完題目,我們會感覺很簡單,但又無從下手。因為這裡包含了左邊界和右邊界,所以我們先定義一個結構體。

struct node
{
  long long b,c;
}a[100010];

然後對它進行排序,或許會有點思路
sort(a+1,a+1+n);//排序,為之後dp做準備 

因為這是結構體的排序,所以我們需要自定義一個排序函式

bool cmp( node x, node y)//
自定義排序方法 { if(x.c!=y.c) return x.c<y.c; return x.b<y.b; }
sort(a+1,a+1+n,cmp);//排序,為之後dp做準備

然後便開始dp

ans=dp[1]=a[1].c-a[1].b+1;//這有個小細節,就是需+1後結果才正確 
for(long long i=2;i<=n;i++)
{
    dp[i]=a[i].c-a[i].b+1;//需+1
    for(long long j=1;j<=i-1;j++)
    {
        if(a[j].c<a[i].b)//如果後一個的左邊界比前一個的右邊界大 
{ dp[i]=max(dp[i],dp[j]+(a[i].c-a[i].b+1));//dp求最大值 ,同樣需+1 } } ans=max(ans,dp[i]);//取最大值 }

於是,程式碼便出來了

#include<bits/stdc++.h>
using namespace std;
long long n,ans;
struct node
{
    long long b,c;
}a[100010];
bool cmp( node x, node y)//自定義排序方法 
{
    if(x.c!=y.c) return x.c<y.c;
    return x.b<y.b;
}
long long dp[100010];
int main()
{
    cin>>n; 
    for(long long i=1;i<=n;i++)
    {
        cin>>a[i].b>>a[i].c;
    }
    sort(a+1,a+1+n,cmp);//排序,為之後dp做準備 
    for(long long i=1;i<=n;i++)
    {
        cout<<a[i].b<<' '<<a[i].c<<endl;
    }
    ans=dp[1]=a[1].c-a[1].b+1;//這有個小細節,就是需+1後結果才正確 
    for(long long i=2;i<=n;i++)
    {
        dp[i]=a[i].c-a[i].b+1;
        for(long long j=1;j<=i-1;j++)
        {
            if(a[j].c<a[i].b)//如果後一個的左邊界比前一個的右邊界大 
            {
                dp[i]=max(dp[i],dp[j]+(a[i].c-a[i].b+1));//dp求最大值 
            }    
        }
        ans=max(ans,dp[i]);//取最大值 
    }
    cout<<ans;
    return 0;
}

這是一道很好的dp題,可以使我們對dp的理解更深刻。所以,快去做一做吧!