贪心部分小结

UVA10382 最少区间覆盖,一块矩形草坪,中心处有一些喷水装置,装置坐标为xi,喷水半径为ri,求最少几个装置可以全部覆盖草坪,求出每个装置能覆盖的矩形,问题转化为最少区间覆盖问题,按区间左端点排序,保存下当前能覆盖到的最远点,从左端点在最远点的左边的区间中选择右端点最大的装置,然后更新最远点。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=18800

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3+10;
struct Node{
    double l,r;
    bool operator < (const Node &rhs) const {
        if(l == rhs.l) return r < rhs.r;
        return l < rhs.l;
    }
};
int main()
{
    int n,l,w;
    while(scanf("%d%d%d",&n,&l,&w)==3) {
        vector<Node> v;
        for(int i = 0; i < n; ++i) {
            double a,r;scanf("%lf%lf",&a,&r);
            if(r <= w/2.0) continue;
            double d = sqrt(r*r-(w+0.0)*(w+0.0)/4);
            double L = a-d,R = a+d;
            v.push_back((Node){L,R});
        }
        sort(v.begin(),v.end());
        double pos = 0,t = 0;
        int ans = 0;
        for(unsigned i = 0; i < v.size(); ++i) {
            if(v[i].l <= pos) t = max(t,v[i].r); ///左端点在pos之前,用右端点跟下一次的最远点
            else { ///更新最远点
                pos = t;
                ++ans;
                if(v[i].l > pos) break;
                --i;
            }
            if(t >= l) { ///已经全部覆盖了
                pos = t;
                ++ans;
                break;
            }
        }
        if(pos < l) ans = -1;
        printf("%d\n",ans);
    }
    return 0;
}

UVA10905 给出n个正整数,连接成最大的整数。因为位数一样所以直接按照字典序比较就行。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=19323

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2+10;
string s[maxn];
bool cmp(const string &a,const string &b)
{
    string t1 = a+b,t2 = b+a; ///直接拼接之后判断字典序,避免复杂的讨论
    return t1 > t2;
}
int main()
{
    int n;
    while(cin>>n) {
        if(n==0) return 0;
        for(int i = 0; i < n; ++i) cin>> s[i];
        sort(s,s+n,cmp);
        for(int i = 0; i < n; ++i) cout<<s[i];
        cout<<endl;
    }
    return 0;
}
UVALIVE 4254 二份之后优先队列贪心,n个任务,第i个要在[ri,di]内执行,工作量为wi,问处理器的速度至少为多少工作量才能执行完所有任务。先二份处理器速度v,问题转化为能否在速度v下执行完所有任务,按时间片给处理器分配任务(这也是操作系统所采用的算法),在第t秒开始的时候将ri等于t的任务加入队列中,取出队列中截止时间最早的任务,如果截止时间小于t,说明当前速度不可能执行完毕,否则将这个任务的工作量减去v,重新加入队列,速度减去工作量,当速度为0时进入下一秒。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=11136

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000 + 10;
struct Node{
    int l,r,w;
    bool operator < (const Node &rhs) const{
        return r > rhs.r;
    }
}a[maxn];
bool check(int v,int tot) ///抢占式处理,结束的早的优先处理
{
    priority_queue<Node> Q;
    int idx = 0;
    for(int t = 1; t <= 20000; ++t) {
        while(idx < tot && a[idx].l < t) Q.push(a[idx++]);///可以在时刻t处理一次的任务加入队列
        int lft = v;///这1s内能处理的工作量
        while(lft && !Q.empty()) {
            Node tmp = Q.top();Q.pop();
            if(tmp.r < t) return false;///存在结束时间小于t的还没
            if(tmp.w > lft) {
                tmp.w -= lft;
                lft = 0;
                Q.push(tmp);
            }else {
                lft -= tmp.w;
            }
        }
    }
    return Q.empty();
}
bool cmp(const Node &a,const Node &b){return a.l < b.l;}
int main()
{
    int T;scanf("%d",&T);
    while(T--) {
        int n;scanf("%d",&n);
        int tot = 0;
        int low = 0, high = 1e7+20;
        for(int i = 0; i < n; ++i) {
            int L,R,w;
            scanf("%d%d%d",&L,&R,&w);
            a[tot++] = (Node){L,R,w};
        }
        sort(a,a+tot,cmp);
        while(low < high) {
            int mid = (low+high)>>1;
            if(check(mid,tot)) high = mid;
            else low = mid+1;
        }
        printf("%d\n",low);
    }
    return 0;
}

UVA 11134 优先队列贪心,N×N的格子上放n个车,第i个车必须在矩形i的范围里,求一种可行的方案,行和列相互独立,先处理出第i行应该放那个车,然后处理第i列应该放那个车,在确定第i行的时候选择矩形行范围包括第i行的,且结束的行下界结束的最早的那个矩形对应的车,和上一个题类似的道理,确定行的时候也是如此。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=19552

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5000 + 10;
struct Node{
    int s,e;
}x[maxn],y[maxn],row[maxn],ans[maxn];
int id[maxn],tid[maxn];
bool cmpx1(const int &i, const int &j)
{
    return x[i].s < x[j].s;
}
struct cmpx2{
    bool operator () (const int &i,const int &j) const {
        return x[j].e < x[i].e;
    }
};
bool cmpy1(const int &i, const int &j)
{
    return row[i].s < row[j].s;
}
struct cmpy2{
    bool operator () (const int &i, const int &j) const {
        return row[j].e < row[i].e;
    }
};
void setid(int n)
{
    for(int i = 1; i <= n; ++i) id[i] = i;
}
bool solve(int n)
{
    setid(n);
    sort(id+1,id+n+1,cmpx1);
    int cur = 1;
    priority_queue<int,vector<int>,cmpx2> Q1;
    for(int i = 1; i <= n; ++i) {
        while(cur <= n && x[id[cur]].s <= i) Q1.push(id[cur++]);
        if(Q1.empty()||x[Q1.top()].e < i) return false;
        int t = Q1.top();Q1.pop();
        row[i] = y[t];
        tid[i] = t;
        ans[t].s = i;
    }

    setid(n);
    sort(id+1,id+n+1,cmpy1);
    cur = 1;
    priority_queue<int,vector<int>,cmpy2> Q2;
    for(int i = 1; i <= n; ++i) {
        while(cur <= n && row[id[cur]].s <= i) Q2.push(id[cur++]);
        if(Q2.empty()||row[Q2.top()].e < i) return false;
        int t = Q2.top();Q2.pop();
        ans[tid[t]].e = i;
    }
    return true;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1&&n) {

        for(int i = 1; i <= n; ++i) {
            scanf("%d%d%d%d",&x[i].s,&y[i].s,&x[i].e,&y[i].e);
        }
        if(!solve(n)) puts("IMPOSSIBLE");
        else {
            for(int i = 1; i <= n; ++i) printf("%d %d\n",ans[i].s,ans[i].e);
        }
    }
    return 0;
}

UVA 11100 鸽巢原理,n个包,每个容量为ai,容量大的可以装一个容量小的包装进去(相同的装不下),求最少几个包可以装下所有包,输出需要多少个包和每个包里装的包,答案为定义cnt(i)为容量为i的包的个数,则答案就是cnt值最大的,记为k,按照容量排序,每隔k个包放在一起,不难发现一定不会有容量相同的包在一个集合里,若选择的小于k,则一定会有容量相同的在一个集合里(鸽巢原理)。而且k个包的个数是接近平均数的,所以包数最大的那个包的个数使可行解中最优的。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=19518

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000 + 10;
int a[maxn];
int main()
{
    int n;
    bool flag = 1;
    while(scanf("%d",&n)==1&&n) {
        for(int i = 0; i < n; ++i) scanf("%d",a+i);
        sort(a,a+n);
        int k = 1,cnt = 1;
        for(int i = 1; i <= n; ++i) {
            if(i==n||a[i]!=a[i-1]) {
                k = max(k,cnt);
                if(a[i]!=a[i-1])cnt = 0;
            }
            ++cnt;
        }
        if(flag) flag = 0;
        else puts("");
        printf("%d\n",k);
        for(int i = 0; i < k; ++i) {
            for(int j = i; j < n; j += k) printf("%d%c",a[j]," \n"[j+k>=n]);
        }
    }
    return 0;
}

UVALIVE 4725,二分,一个机场有W和E两个通道,只有一个跑道,每秒可以从跑道起飞一架飞机,告诉你每个时刻进入两个通道的飞机数,求通道最小的可能容量,二分容量,判断能否在容量不超过v的情况下让飞机进入通道,递推i时刻开始时(此时i时刻的飞机还没进入)能从W,E,和跑道飞走的飞机数。判断的时候看时刻i需要从W和E飞走的飞机数是否大于能从W和E飞走的飞机数,还需判断和是否大于能从跑道飞走的飞机数。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=11607

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000 + 10;
int a[maxn],b[maxn],lx[maxn],ly[maxn],lf[maxn];
bool check(int k,int n)
{
    int x = 0, y = 0,Mx = 0,My = 0;
    for(int i = 1; i <= n; ++i) {
        x = a[i];
        y = b[i];
        int lft = lf[i];
        Mx = max(Mx,x-k);
        My = max(My,y-k);
        if(Mx + My > lft || lx[i] < Mx || ly[i] < My) return false;
    }
    return true;
}
int main()
{
    int n,T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        a[0] = b[0] = 0;
        lx[0] = ly[0] = 0;
        lf[0] = 0;
        int sa = 0,sb = 0,su = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d",a+i,b+i);
            lx[i] = lx[i-1] + (sa > lx[i-1]); ///能从a通道飞走的飞机
            ly[i] = ly[i-1] + (sb > ly[i-1]); ///能从b通道飞走的飞机
            lf[i] = lf[i-1] + (su > lf[i-1]); ///能从跑道飞走的飞机
            sa += a[i];
            sb += b[i];
            su += (a[i]+b[i]);
        }
        for(int i = 1; i <= n; ++i) {
            a[i] += a[i-1];
            b[i] += b[i-1];
        }
        int L = 1, R = 2e5;
        while(L < R) {
            int mid = (L+R)>>1;
            if(check(mid,n)) R = mid;
            else L = mid+1;
        }
        printf("%d\n",L-1);
    }
    return 0;
}

UVALIVE 4850 不理解,先放着,有n个服务需要安装,第i个需要si的时间安装,若安装完成时间ti晚于di,则惩罚值为di-ti,求惩罚值最大的两个服务的和的最小值。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=11732

#include <bits/stdc++.h>
const int maxn = 500+10;
using namespace std;
struct Node{
    int last,ed;
    bool operator < (const Node & rhs) const {
        if(ed == rhs.ed) return last < rhs.last;
        return ed < rhs.ed;
    }
}a[maxn];
bool Modify(int *m,int add)
{
    if(add > m[0]) {
        m[0] = add;
        if(m[0] > m[1]) swap(m[0],m[1]);
        return true;
    }
    return false;
}
int check(int x,int pos) ///尝试让x最后安装
{
    int curTime = 0;
    int m[2] = {0,0};
    for(int i = 0; i <= pos; ++i) {
        if(i == x) continue;
        curTime += a[i].last;
        int add = max(0,curTime-a[i].ed);
        Modify(m,add);
    }
    curTime += a[x].last;
    int add = max(0,curTime-a[x].ed);
    Modify(m,add);
    return m[0]+m[1];
}
int main()
{
    int T;scanf("%d",&T);
    while(T--) {
        int n;scanf("%d",&n);
        for(int i = 0; i < n; ++i) {
            scanf("%d%d",&a[i].last,&a[i].ed);
        }
        sort(a,a+n);
        int curTime = 0,m[2] = {0,0},pos = 0;
        for(int i = 0; i < n; ++i) {
            curTime += a[i].last;
            int add = max(0,curTime-a[i].ed);
            if(Modify(m,add)) pos = i;
        }
        int ans = 2e9;
        for(int i = 0; i < n; ++i) ans = min(ans,check(i,pos));
        printf("%d\n",ans);
    }
    return 0;
}

UVALIVE 3266 田忌赛马,双指针扫描一下,给出田忌和齐王n匹马的速度,每次选择一匹马和齐王的马比赛,输了负100,赢了加100,平局不变,求田忌最多能得多少分,排序之后双指针扫描下。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=9442

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 10;
int a[maxn],b[maxn];
int main()
{
    int n;
    while(scanf("%d",&n)==1&&n) {
        for(int i = 0; i < n; ++i) scanf("%d",a+i);
        for(int i = 0; i < n; ++i) scanf("%d",b+i);
        sort(a,a+n);
        sort(b,b+n);
        int x = 0,y = 0,ex = n,ey = n,ans = 0;
        while(x < ex) {
            if(a[x] > b[y]) { ///能赢直接走
                ++ans;
                ++x;
                ++y;
            }else if(a[ex-1] > b[ey-1]) { ///能赢直接走
                ++ans;
                --ex;
                --ey;
            }else {
                if(a[x] < b[ey-1]) --ans;///否则用最差的和最好的比
                ++x;
                --ey;
            }
        }
        printf("%d\n",ans*200);
    }
    return 0;
}

UVA 11389,排序之后贪心,最小的和最大的匹配,n个司机,n个午间和n个夜间路线,给每个司机安排一个午间和夜间路线,使得每个路线恰好被分配到一个司机,如果一个司机的工作时间ti大于d,则会收取(t-d)×r的加班费,输出总的最小加班费。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=19807

#include <bits/stdc++.h>
const int maxn = 1e2+10;
int a[maxn],b[maxn];
using namespace std;
int solve(int n,int d)
{
    int ans = 0;
    for(int i = 0; i < n; ++i) {
        ans += max(0,a[i]+b[i]-d);
    }
    return ans;
}
int main()
{
    int n,d,r;
    while(scanf("%d%d%d",&n,&d,&r)==3) {
        if(n==0)return 0;
        for(int i = 0; i < n; ++i) scanf("%d",a+i);
        for(int i = 0; i < n; ++i) scanf("%d",b+i);
        sort(a,a+n);
        for(int i = 0; i < n; ++i) {
            for(int j = i+1; j < n; ++j) {
                int t1 = solve(n,d);
                swap(b[i],b[j]);
                int t2 = solve(n,d);
                if(t1 < t2) swap(b[i],b[j]);
            }
        }
        int ans = solve(n,d);
        printf("%d\n",ans*r);

    }
    return 0;
}

UVALIVE 4636,逻辑推理,用一些等大的立方体搭积木,每个立方体或者直接放在网格或者立方体的上面,给出正视图每一列的高度,侧视图每一行的高度,问最少需要多少个立方体,思路若a[r][c]高度为h,且从侧视图看第r行和从正视图看第c列高度也为h,显然只需要在a[r][c]处放h个积木,第r和和第c列都能得到满足,于是我们可以n×m枚举,那些格子可以同事满足r和c,不能满足的我们就需要放两个,具体位置不用考虑

http://acm.bnu.edu.cn/v3/problem_show.php?pid=11518

#include <bits/stdc++.h>
const int maxn = 1e2+10;
int h[maxn],w[maxn];
using namespace std;

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2&&(n+m)) {
        int ans = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d",h+i);ans+=h[i];
        }
        for(int i = 1; i <= m; ++i) {
            scanf("%d",w+i);ans+=w[i];
        }
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                if(h[i] == w[j]) {
                    ans -= w[j];
                    w[j] = 0;
                    break;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

UVALIVE 2757 优先队列贪心,n个商品,第i件商品在di之前出售可以获得pi的价值,出售1件商品需要1s,求最大价值,倒着枚举时间,将结束时间不晚于枚举时间的加入队列里,选择队列里价值最大的出售

http://acm.bnu.edu.cn/v3/problem_show.php?pid=8933

#include <bits/stdc++.h>
const int maxn = 1e4+10;
using namespace std;
struct Node{
    int p,d;
    bool operator < (const Node & rhs) const {
        return p < rhs.p;
    }
}a[maxn];
bool cmp(const Node & a,const Node &b)
{
    return a.d > b.d;
}
int solve(int n)
{
    sort(a,a+n,cmp);
    int cur = 0,ans = 0;
    priority_queue<Node>Q;
    for(int t = a[0].d; t >= 0; --t) {
        while(cur < n && a[cur].d > t) Q.push(a[cur++]);///t时刻可以选择出售的商品
        while(!Q.empty()) {
            Node tmp = Q.top();Q.pop();
            if(tmp.d <= t)continue;
            ans += tmp.p;
            break;
        }
    }
    return ans;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1) {
        for(int i = 0; i < n; ++i) {
            scanf("%d%d",&a[i].p,&a[i].d);
        }
        printf("%d\n",solve(n));
    }
    return 0;
}

UVALIVE 3507 优先队列贪心,n个炼钢订单,每个订单描述为(qi,di)qi表示要qi吨刚,完成时间不得晚于di,每单位时间能生产1吨刚,问最多能满足多少个订单,先按di排序订单,记录当前时间,先把当前时间加上qi,然后将qi加入队列。如果当前时间大于di,则从队列中删去q最大的那个订单,从当前时间中减去q,直到当前时间不大于di。最终队列的大小就是答案。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=9683

#include <bits/stdc++.h>
const int maxn = 8e5+10;
using namespace std;
struct Node{
    int p,d;
    bool operator < (const Node & rhs) const {
        return d < rhs.d;
    }
}a[maxn];
int solve(int n)
{
    priority_queue<int>Q;
    sort(a,a+n);
    int t = 0;
    for(int i = 0; i < n; ++i) {
        Q.push(a[i].p);
        t += a[i].p;
        while(t > a[i].d) {
            t -= Q.top();
            Q.pop();
        }
    }
    return Q.size();
}
int main()
{
    int T,n;scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        for(int i = 0; i < n; ++i) {
            scanf("%d%d",&a[i].p,&a[i].d);
        }
        printf("%d\n",solve(n));
        if(T)puts("");
    }
    return 0;
}
UVALIVE 4324 水模拟,给出屏幕上的窗口信息,按字典序输出顶层窗口的id。只需要判断窗口的帧是否没被覆盖,窗口内部是否无其他窗口。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=11206

#include <bits/stdc++.h>
const int maxn = 1e2+10;
using namespace std;
char s[maxn][maxn];
bool vis[maxn][maxn];
int cnt[300];
bool check(int x,int y)
{
    if(vis[x][y]) return false;
    vis[x][y] = 1;
    char c = s[x][y];
    if(c < 'A'||c > 'Z') return false;
    int w = 1,h = 1;
    int tot = 0;
    while(s[x+w][y]==c) {
        vis[x+w][y] = 1;
        ++tot;
        ++w;
    }
    while(s[x][y+h]==c) {
        vis[x][y+h] = 1;
        ++tot;
        ++h;
    }
    if(w < 3||h < 3)return false;
    x += w-1;
    y += h-1;
    int tw = w,th = h;
    if(s[x][y]!=c) return false;
    while(h>0&&s[x][y-h+1]==c) {
        vis[x][y-h+1] = 1;
        ++tot;
        --h;
    }
    while(w>0&&s[x-w+1][y]==c) {
        vis[x-w+1][y] = 1;
        ++tot;
        --w;
    }
    if(w+h==0&&tot == cnt[c+0]+2) {
        x -= tw-1;
        y -= th-1;
        for(int i = 1; i + 1< tw; ++i) {
            for(int j  = 1; j + 1 < th; ++j) {
                if(s[x+i][y+j]!='.') return false;
            }
        }
    }
    return true;
}
string solve(int n,int m)
{
    memset(vis,0,sizeof vis);
    string ans;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            if(check(i,j))ans += s[i][j];
        }
    }
    sort(&ans[0],&ans[0]+ans.size());
    return ans;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)==2&&(n+m)) {
        memset(s,0,sizeof s);
        memset(cnt,0,sizeof cnt);
        for(int i = 0; i < n; ++i) {
            scanf("%s",s[i]);
            for(int j = 0; j < m; ++j) ++cnt[s[i][j]+0];
        }
        string ans = solve(n,m);
        cout<<ans<<endl;
    }
    return 0;
}

UVALIVE 4328,Jhon要去参加n个婚礼仪式,第i个婚礼仪式在[si,ti]里举行,在第i个婚礼的时间必须超过婚礼的一半,为是否所有的婚礼都能满足条件,按照婚礼的中间时间排序,记录当前时间,若当前时间大于等于中点时间,则无法满足,否则更新当前时间。

http://acm.bnu.edu.cn/v3/problem_show.php?pid=11210

#include <bits/stdc++.h>
const int maxn = 1e5+10;
using namespace std;
struct Node{
    int l,r,mid;
    bool operator < (const Node & rhs) const {
        if(mid == rhs.mid) return l > rhs.l;
        return mid < rhs.mid;
    }
}a[maxn];
bool solve(int n)
{
    sort(a,a+n);
    int curTime = 0;
    for(int i = 0; i < n; ++i) {
        if(curTime >= a[i].mid) return false;
        curTime = max(curTime,a[i].l);
        curTime += a[i].mid - a[i].l;
    }
    return true;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1&&n) {
        for(int i = 0; i < n; ++i) {
            scanf("%d%d",&a[i].l,&a[i].r);
            a[i].mid = (a[i].l+a[i].r)>>1;
        }
        puts(solve(n)?"YES":"NO");
    }
    return 0;
}
未能AC题目UVA 11627,LA4094 (题意没懂)


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值