饥饿的牛 线性dp内的区间

Posted star_eternal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了饥饿的牛 线性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;
}

  

以上是关于饥饿的牛 线性dp内的区间的主要内容,如果未能解决你的问题,请参考以下文章

[区间+线性dp]数字游戏

[luoguP1868] 饥饿的奶牛(DP)

如何通过单击片段内的线性布局从片段类开始新活动?下面是我的代码,但这不起作用

bzoj1710/Usaco2007 OpenCheappal 廉价回文——区间dp

贪心算法----区间覆盖问题(POJ2376)

在android中的类内的对话框片段的线性布局中添加textview