您的位置:首页 > 其它

【codevs】线段覆盖系列 贪心&&动规

2015-10-09 18:40 399 查看

线段覆盖

贪心,不说了。

代码:

[code]#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int size=1000010;
struct edge{
    int l,r;
}l[size];

bool cmp(const edge &a,const edge &b)
{
    return a.r<b.r;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
    {
        scanf("%d%d",&l[i].l,&l[i].r);
        if(l[i].l>l[i].r) swap(l[i].l,l[i].r);
    }
    sort(l+1,l+1+n,cmp);
    int ans=0;
    for(int i=1,last=-2333;i<=n;i++)
    {
        if(last<=l[i].l)
        {
            last=l[i].r;
            ans++;
        }
    }
    printf("%d",ans);
    return 0;
}


线段覆盖2

这个是dp。

按右端点排序。

dp[i]代表当第i个线段是被选择的最后一个线段后,所达到的最大价值。

所以状态转移方程:

[code]dp[i]=max{dp[i],dp[j]+l[i].d} (j<i && l[i].l>=l[j].r)


代码:

[code]#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int size=23333;

int dp[size];

struct edge{
    int l,r,d;
}l[size];

bool cmp(const edge &a,const edge &b)
{
    return a.r<b.r;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&l[i].l,&l[i].r,&l[i].d);
    sort(l+1,l+1+n,cmp);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        dp[i]=l[i].d;
        for(int j=1;j<i;j++)
        {
            if(l[j].r<=l[i].l)
            {
                dp[i]=max(dp[i],dp[j]+l[i].d);
            }
        }
        ans=max(dp[i],ans);
    }
    printf("%d",ans);
    return 0;
}
/*
10
7 8 1
1 7 2
0 3 3
4 9 4
0 6 5
5 7 6
0 3 7
7 8 8
7 10 9
4 7 10
*/


线段覆盖3

贪心,和第一个一样。

线段覆盖4

这个也是dp,不过n太大,不能n^2。

可以改变状态的表示。

dp[i]代表选到坐标i的时候所拿到的最大价值。

状态转移方程:

[code]dp[i]=max{ dp[i],max{ dp[1],dp[2],...,dp[i-1] }+l[i].d }


但因为是线段,所以可以这样:

[code]dp[l[i].r]=max{ dp[i],max{dp[1],dp[2]...,dp[l[i].l]}+l[i].d }


因为要先确定
dp[l[i].l]
,所以应该把坐标按左端点排序。

如何选取
1~l[i].l
的最大值?

树状数组!

这样就优化到O(nlogn)

代码:

[code]#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL size=1000010;
const LL INF=(LL)1e15;

struct edge{
    LL l,r;
    LL d;
}l[size];

LL dp[size];

bool cmp(const edge &a,const edge &b)
{
    return a.l<b.l;
}

LL bits[size];
void add(LL x,LL d)
{
    for(LL i=x;i<=size-10;i+=i&(-i))
    {
        bits[i]=max(bits[i],d);
    }
}

LL ask(LL x)
{
    LL ans=0;
    for(LL i=x;i>0;i-=i&(-i))
    {
        ans=max(ans,bits[i]);
    }
    return ans;
}

int main()
{
    LL n;
    scanf("%lld",&n);
    for(LL i=1;i<=n;i++) scanf("%lld%lld%lld",&l[i].l,&l[i].r,&l[i].d);

    sort(l+1,l+1+n,cmp);
    LL ans=0;
    for(LL i=1;i<=n;i++)
    {
        dp[l[i].r]=max(dp[l[i].r],ask(l[i].l)+l[i].d);
        ans=max(ans,dp[l[i].r]);
        add(l[i].r,dp[l[i].r]); 
    }
    printf("%lld",ans);
    return 0;
}


线段覆盖5

坐标离散化,就和4一样了。

听说卡P党?

代码:

[code]#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL size=2000010;
const LL INF=(LL)1e15;

struct edge{
    LL l,r;
    LL d;
}l[size];

bool cmp(const edge &a,const edge &b)
{
    return a.l<b.l;
}

LL lsh[size];
LL dp[size],bits[size];

void add(LL x,LL d)
{
    for(LL i=x;i<=size-10;i+=i&-i)
    {
        bits[i]=max(bits[i],d);
    }
}

LL ask(LL x)
{
    LL ans=0;
    for(LL i=x;i>0;i-=i&-i)
    {
        ans=max(bits[i],ans);
    }
    return ans;
}

int main()
{
    LL n;
    scanf("%lld",&n);
    for(LL i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld",&l[i].l,&l[i].r,&l[i].d);
        lsh[++lsh[0]]=l[i].l; 
        lsh[++lsh[0]]=l[i].r; 
    }
    sort(lsh+1,lsh+1+lsh[0]);
    LL len=unique(lsh+1,lsh+1+lsh[0])-lsh-1;
    for(LL i=1;i<=n;i++) 
    {
        l[i].l=lower_bound(lsh+1,lsh+1+len,l[i].l)-lsh;
        l[i].r=lower_bound(lsh+1,lsh+1+len,l[i].r)-lsh;
    }
    //for(LL i=1;i<=n;i++) printf("%d %d %d\n",l[i].l,l[i].r,l[i].d);
    sort(l+1,l+1+n,cmp);
    LL ans=0;
    for(LL i=1;i<=n;i++)
    {
        dp[l[i].r]=max(dp[l[i].r],l[i].d+ask(l[i].l));
        ans=max(ans,dp[l[i].r]);
        add(l[i].r,dp[l[i].r]);
    }
    printf("%lld",ans);

    return 0;
}
/*
5
233 2333 1
100 1000 2
123 321 3
444 555 4
12 450 5
*/


总结:序列型动规应该是比较简单的,但刷多了还是恶心…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: