飢餓的奶牛(題解)
阿新 • • 發佈:2020-08-17
這是一道很好的訓練dp的題,並且有很多細節需要注意
原題如下:
飢餓的奶牛
描述
牛在飼料槽前排好了隊。飼料槽依次用1到N(1≤N≤2000)編號。每天晚上,一頭幸運的牛根據約翰的規則,吃其中一些槽裡的飼料。
約翰提供N個區間的清單。一個區間是一對整數l,r(1≤l≤r≤N),表示一些連續的飼料槽,比如1-3,7-8,3−4等等。牛可以任意選擇區間,但是牛選擇的區間不能有重疊。
當然,牛希望自己能夠吃得越多越好。給出一些區間,幫助這隻牛找一些區間,使它能吃到最多的東西。
在上面的例子中,1-3和3−4是重疊的;聰明的牛選擇1−3,7−8,這樣可以吃到5個槽裡的東西。
輸入
第一行,整數N(1≤N≤2000)。
第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的理解更深刻。所以,快去做一做吧!