UVa:10148 Advertisement(贪心)

贪心。要求每个区间至少有k个点覆盖,如果区间长度不足k则全部有点覆盖。

根据区间右端点从小到大排序,如果右端点相同则根据左从小到大排序。对于每个区间选取右边k个端点。这里有个问题就是,如果该段区间已经选过一部分点了,那需要统计一下已经选过多少点,我这里用了最笨的办法,直接数(由于区间有负数,所以都加了10005来消掉负数),这样再把剩下的点选够即可。

这样最坏的情况是1000*20000,居然没超时。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
#define ll long long
#define INF 200000000
#define VAL 10005
using namespace std;
struct Segment
{
    int L,R;
    Segment(int a,int b):L(a),R(b) {}
    bool operator < (Segment p) const
    {
        if(R==p.R) return L<p.L;
        return R<p.R;
    }
};
vector<Segment> vec;
bool vis[VAL*2];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int k,n;
        scanf("%d%d",&k,&n);
        memset(vis,0,sizeof(vis));
        vec.clear();
        int minn=INF,maxn=0;
        for(int i=0; i<n; ++i)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if(l>r) swap(l,r);
            l+=VAL;
            r+=VAL;
            minn=min(l,minn);
            maxn=max(r,maxn);
            vec.push_back(Segment(l,r));
        }
        sort(vec.begin(),vec.end());
        for(int i=0; i<vec.size(); ++i)
        {
            int l=vec[i].L,r=vec[i].R;
            int c=0;
            if(i==0||vec[i-1].R<vec[i].L) c=0;
            else
            {
                for(int j=l; j<=r; ++j)
                    if(vis[j]) c++;
            }
            if(c<k)
            {

                for(int j=r; j>=l&&c<k; --j)
                    if(!vis[j])
                    {
                        vis[j]=true;
                        c++;
                    }
            }
        }
        vector<int> ans;
        for(int i=minn; i<=maxn; ++i)
            if(vis[i]) ans.push_back(i-VAL);
        printf("%d\n",ans.size());
        for(int i=0; i<ans.size(); ++i)
            printf("%d\n",ans[i]);
        if(T) printf("\n");
    }

    return 0;
}


 

你可能感兴趣的:(贪心)