区间贪心问题

博客探讨了如何使用贪心策略解决涉及区间的数学问题。通过按l从小到大排列区间,找到覆盖1到n所需的最小区间数。此外,还讨论了按r排序并切割未被切割过的线条的方法,以及在确保区间不相交的情况下,求和为k的区间最大数量的问题。文章提供了多个AC代码实例来解释和验证这些贪心算法的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://ac.nowcoder.com/acm/contest/392/A
解析:

给定n个区间,求覆盖1~n需要最小的区间数目

用贪心解决,l从小到大排,遍历找到   l<=g中r最大的,更新

ac:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;

struct node
{
    int l,r;
}ee[MAXN];

bool cmp(node a,node b)
{
    return a.l<b.l;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
        scanf("%d%d",&ee[i].l,&ee[i].r);
    sort(ee,ee+m,cmp);
    int flag=0,sum=0,i=0,g=1;
    while(i<m)
    {
        int maxs=0;
        for(i;i<m&&ee[i].l<=g;i++)//(i<m)不写会数组溢出
            maxs=max(maxs,ee[i].r);
        if(maxs==0)
            break;

        sum++;
        g=maxs+1;
        if(g>=n)
        {
            flag=1;
            break;
        }
    }
    if(flag)
        printf("%d\n",sum);
    else
        printf("-1\n");
    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/984/B
解析:

直接按r排序,切割未被切割过的r最左端的线条

注意不要切割端点,端点被切割不算被切割

ac:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
struct node
{
    int l,r;
    int sig=0;
    friend bool operator <(node a,node b)
    {
        return a.r<b.r;
    }
}ee[MAXN];

int main()
{
    int n,len;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&ee[i].l,&len);
        ee[i].r=ee[i].l+len;
    }
    sort(ee+1,ee+n+1);
    int k=0,sum=0;
    for(int i=1;i<=n;i++)
    {
        if(ee[i].l>k)
        {
            k=ee[i].r-1;//切割端点左边一个位置
            sum++;
        }
    }
    printf("%d\n",sum);
    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/180/C

解析:

区间贪心,记录a去的位置的最小位置

从左往右扫,目标是r点,如果vis[i]<r,目标就降到vis[i],如果到达r,就ans++,r=vis[i]

ac:

#include<bits/stdc++.h>
using namespace std;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
#define min(a, b) (a < b ? a : b)
char buf[(1 << 22)], *p1 = buf, *p2 = buf;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
#define MAXN 1100005
int vis[MAXN];
 
int main()
{
    int n,m,a,b;
    //cin>>n>>m;
    n=read();
    m=read();
    for(int i=0;i<=n;i++)
        vis[i]=99999999;
    while(m--)
    {
        //cin>>a>>b;
        a=read();
        b=read();
        vis[a]=min(vis[a],b);
    }
    int r=99999999,ans=0;
    for(int i=1;i<=n;i++)
    {
        r=min(r,vis[i]);
        if(i==r)
        {
            r=vis[i],ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

http://codeforces.com/contest/1141/problem/F2

题意:

给一个数组,

求一些不相交的区间,每个区间的和为k,求区间的最大数目

解析:

先求前缀和

两层循环遍历区间,将相同区间和的区间装入vector中

最后遍历每一个区间,贪心求最多区间数目

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 3000005
using namespace std;
 
struct node
{
    int x,y;
    bool friend operator <(node a,node b)
    {
        if(a.y==b.y)
            return a.x<b.x;
        else return a.y<b.y;
    }
};
 
int a[MAXN];
int sum[MAXN];
map<ll,int> mp;
vector<node> vc[MAXN];
int cnt;
 
int main()
{
    //freopen("E:/in.txt","r",stdin);
    cnt=1;
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            int cc=sum[j]-sum[i-1];
            if(mp[cc]==0)
            {
                mp[cc]=cnt;
                vc[cnt].push_back({i,j});
                cnt++;
            }
            else{
                vc[mp[cc]].push_back({i,j});
            }
        }
    }
 
    int maxs=0,qc,ans=0;
    for(int i=1;i<cnt;i++)
    {
        int len=vc[i].size();
        int r=0,sum=0;
        sort(vc[i].begin(),vc[i].end());
        for(int j=0;j<vc[i].size();j++)
        {
            if(vc[i][j].x>r)
            {
                r=vc[i][j].y;
                sum++;
            }
        }
        if(sum>ans)
        {
            ans=sum;
            qc=i;
        }
    }
 
    printf("%d\n",ans);
    int r=0;
    for(int i=0;i<vc[qc].size();i++)
    {
        if(vc[qc][i].x>r)
        {
            printf("%d %d\n",vc[qc][i].x,vc[qc][i].y);
            r=vc[qc][i].y;
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值