饥饿的牛 线性dp内的区间
饥饿的牛
牛在饲料槽前排好了队。饲料槽依次用1到N(1<=N<=100000)编号。每天晚上,一头幸运的牛根据约翰的规则,吃其中一些槽里的饲料。
约翰提供B个区间的清单。一个区间是一对整数start-end,1<=start<=end<=N,表示一些连续的饲料槽,比如1-3,7-8,3-4等等。牛可以任意选择区间,但是牛选择的区间不能有重叠。
当然,牛希望自己能够吃得越多越好。给出一些区间,帮助这只牛找一些区间,使它能吃到最多的东西。
在上面的例子中,1-3和3-4是重叠的;聪明的牛选择{1-3,7-8},这样可以吃到5个槽里的东西。
输入
第一行,整数B(1<=B<2000)
第2到B+1行,每行两个整数,表示一个区间,较小的端点在前面。
输出
仅一个整数,表示最多能吃到多少个槽里的食物。
样例
输入:
3
1 3
7 8
3 4
输出:
5
说明:数据前10组为小数据,后10组为大数据,N〈=10000000;B〈=100000
然后那到这道题就有两个想法
1.设f(i)为到前i个点能得到的最大区间
{
如果没有到i的区间f(i)=f(i-1);
否则f(i)=f(所有到i的开始位置的点-1)+区间和;
f(i)=max(f(i-1),f(i));
}
然后用链表优化时间
#include<cstdio> #include<algorithm> #define N1 100000+1 #define N2 2000+1 using namespace std; struct edge{ int next; int to; }; int num,head[N1]; edge e[N2]; void add(int from,int to) { e[++num].next=head[from]; e[num].to=to; head[from]=num; } int f[N1]; bool flag[N1]; int main() { int b,x,y,n=0; scanf("%d",&b); for(int i = 1;i<=b;i++) { scanf("%d%d",&x,&y); add(y,x); if(y>n)n=y; flag[y]=1; } for(int i=1;i<=n;i++) { f[i]=f[i-1]; if(!flag[i])continue; else{ for(int j=head[i];j;j=e[j].next) { int v=e[j].to; f[i]=max(f[i],f[v-1]+(i-v+1)); } } } printf("%d",f[n]); return 0; }
2.设f(i)为前i个区间能获得的最大区间值
貌似要以区间右端点排序
1.f(i)=f(i-1)
2.f(i)=f(不在这个区间内,却最靠近这个区间的左断点)+这个区间的值
f(i)=max{1,2};
时间复杂度O(nlogn);
空间复杂度O(n);
因为排序,所以可以用二分查找优化,否则超时
#include<cstdio> #define maxn 100000+2 using namespace std; int f[maxn],b; struct s_p { int s,e; bool operator <(s_p b) { return s<b.s; } }data[maxn]; void change(s_p &a,s_p &b) { s_p t=a;a=b;b=t; } void sort(int a,int b) { if(a==b)return; s_p val=data[(a+b)/2]; int i=a-1,j=b+1; while(1) { do i++;while(data[i]<val); do j--;while(val<data[j]); if(i>=j)break; change(data[i],data[j]); } sort(a,j); sort(j+1,b); } int find(int a,int B,int c) { if(a==B) { if(data[a].s>=c)return a; return b+1; } int mid=(a+B)/2; if(c<=data[mid].s)return find(a,mid,c); return find(mid+1,B,c); } int main() { // freopen("10034.in","r",stdin); // freopen("10034.out","w",stdout); scanf("%d",&b); for(int i=1;i<=b;i++) scanf("%d%d",&data[i].s,&data[i].e); sort(1,b); for(int i=b;i>=1;i--) { f[i]=f[i+1]; int t=find(1,b,data[i].e+1); if(f[i]<f[t]+data[i].e-data[i].s+1)f[i]=f[t]+data[i].e-data[i].s+1; } printf("%d",f[1]); fclose(stdout); return 0; }
夫君子之行,
静以修身,俭以养德;
非澹泊无以明志,
非宁静无以致远。
夫学须静也,才须学也;
非学无以广才,非志无以成学。
慆慢则不能励精,
险躁则不能冶性。
年与时驰,意与日去,
遂成枯落,多不接世。
悲守穷庐,将复何及!