算法2贪心F

合集原文指路

算法2贪心F

1290: F001 木棒加工问题

题目描述

现有n根木棒,已知它们的长度和重量。要用一部木工机一根一根地加工这些木棒。该机器在加工过程中需要一定的准备时间,是用于清洗机器,调整工具和模板的。木工机需要的准备时间如下:
(1) 第一根木棒需要1min的准备时间;
(2) 在加工了一根长为l,重为w的木棒之后,接着加工一根长为l’(l≤l’),重为w’(w≤w’)的木棒是不需要任何准备时间的。否则需要一分钟的准备时间。
给定n根木棒,你要找到最少的准备时间。例如现在有长和重分别为(4,9),(5,2),(2,1),(3,5)和(1,4)的五根木棒,那么所需准备时间最少为2min,顺序为(1,4),(3,5),(4,9),(2,1),(5,2)。

输入

输入有多组测试例。输入数据的第一行是测试例的个数(T)。每个测试例两行:第一行是一个整数n(1≤n≤5000),表示有多少根木棒;第二行包括n*2个整数,表示l1,w1,l2,w2,l3,w3,…,ln,wn,全部不大于10000,其中li和wi表示第i根木棒的长度和重量。数据由一个或多个空格分隔。

输出

输出是以分钟为单位的最少准备时间,一行一个。

样例输入

3 
5 
4 9 5 2 2 1 3 5 1 4 
3 
2 2 1 1 2 2 
3 
1 3 2 2 3 1

样例输出

2
1
3
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 50;

int n;
bool ck[maxn];
void solve() {
    cin >> n;
    fill(ck, ck + 5050, false);
    vector<pair<int, int>> len;
    for (int i = 0; i < n; i++) {
        int l, w;cin >> l >> w;
        len.push_back(make_pair(l, w));
    }
    sort(len.begin(), len.end());
    int cnt = 0, ans = 0;
    while (cnt < n) {
        ans++;
        int ki = 0;
        int li = 0, wi = 0;
        for (int i = 0;i < n;i++) {
            if (!ck[i]) {
                ki = i;
                li = len[i].first, wi = len[i].second;
                ck[i] = true;
                cnt++;
                break;
            }
        }
        // cout << ki << " " << li << " " << wi << endl;
        for (int i = 0;i < n;i++) {
            if (ck[i])continue;
            if (li <= len[i].first && wi <= len[i].second) {
                ck[i] = true;
                cnt++;
                li = len[i].first, wi = len[i].second;
            }
        }
    }
    cout << ans << endl;
}
int main() {
    int t;cin >> t;
    while (t--)
        solve();

    return 0;
}

1291: F002 装箱

题目描述

一个工厂生产的产品形状都是长方体,高度都是h,主要有1x1,2x2,3x3,4x4,5x5,6x6等6种。这些产品在邮寄时被包装在一个6x6xh的长方体包裹中。由于邮费很贵,工厂希望减小每个订单的包裹数量以增加他们的利润。因此他们需要一个好的程序帮他们解决这个问题。你的任务就是设计这个程序。

输入

输入包括多组测试数据,每一行代表一个订单。每个订单里的一行包括六个整数,用空格隔开,从小到大分别为这6种产品的数量。6个0表示文件结束。

输出

针对每个订单输出一个整数,占一行,代表对应的订单所需的最小包裹数。没有多余的空行。

样例输入

0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0

样例输出

2
1
AC代码
// #include<bits/stdc++.h>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 50;

int n;
int b1, b2, b3, b4, b5, b6;
int l3[4] = { 0,7,6,5 };
int l2[4] = { 0,5,3,1 };
int l1[9] = { 0,32,28,24,20,16,12,8,4 };
void solve() {
    int ans = b6 + b5 + b4 + (b3 + 3) / 4;
    int n2 = 5 * b4 + l2[b3 % 4];;
    if (n2 >= b2) {
        int n1 = b5 * (36 - 25) + (n2 - b2) * 4 + l3[b3 % 4];
        if (n1 < b1)
            ans += (b1 - n1 + 35) / 36;
    }
    else {
        int m2 = b2 - n2;
        ans += (m2 + 8) / 9;
        int n1 = b5 * (36 - 25) + l3[b3 % 4] + l1[m2 % 9];
        if (n1 < b1)
            ans += (b1 - n1 + 35) / 36;
    }
    cout << ans << endl;
}

int main() {
    while (cin >> b1 >> b2 >> b3 >> b4 >> b5 >> b6 && (b1 || b2 || b3 || b4 || b5 || b6))
        solve();
}

1292: F003 移动桌子

题目描述

著名的ACM(Advanced Computer Maker)公司租用了一层有400个房间的办公楼,结构如下。

F003.png

这层楼沿着走廊南北向的两边各有200个房间。最近,公司要做一次装修,需要在各个办公室之间搬运办公桌。由于走廊狭窄,办公桌都很大,走廊里一次只能通过一张办公桌。必须制定计划提高搬运效率。经理制定如下计划:一张办公桌从一个房间移动到另一个房间最多用十分钟。当从房间i移动一张办公桌到房间j,两个办公室之间的走廊都会被占用。所以,每10分钟内,只要不是同一段走廊,都可以在房间之间移动办公桌。为了说得更清楚一些,经理举例说明哪些情况可以同时移动,哪些情况不能同时移动。

F0032.png

每个房间,只有一张办公桌进出。现在,经理想找到一种方案,使移动桌子的事情尽快完成。请编写程序解决经理的难题。

输入

输入数据有T组测试例,在第一行给出测试例个数(T)。每个测试例的第一行是一个整数N(1≤N≤200),表示要搬运办公桌的次数。接下来N行,每行两个正整数s和t,表示一张桌子,是从房间号码s移到房间号码t。有多组输入数据,输入第一行为一个表示输入数据总数的整数N,然后是N组输入数据。

输出

每组输入都有一行的输出数据,为一整数T,表示完成任务所花费的最少时间。

样例输入

2 
4 
10 20 
30 40 
50 60 
70 80 
2 
1 3 
2 200

样例输出

10
20
AC代码
// #include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 50;

int n;
void solve() {
    cin >> n;
    int pass[220] = {};
    for (int i = 1;i <= n;i++) {
        int x, y;cin >> x >> y;
        x = (x + 1) / 2;
        y = (y + 1) / 2;
        if (x > y) {
            x = x ^ y;y = x ^ y;x = x ^ y;
        }
        for (int j = x;j <= y;j++) {
            pass[j]++;
        }
    }
    int ans = *max_element(pass + 1, pass + 201);
    cout << 10 * ans << endl;
}

int main() {
    int t;cin >> t;
    while (t--)
        solve();
}

1293: F004 基因集合

题目描述

随着大量的基因组DNA序列数据被获得,它对于了解基因越来越重要(基因组DNA的一部分,是负责蛋白质合成的)。众所周知,在基因组序列中,由于存在垃圾的DNA中断基因的编码区,真核生物(相对于原核生物)的基因链更加复杂。也就是说,一个基因被分成几个编码片段(称为外显子)。虽然在蛋白质的合成过程中,外显子的顺序是固定的,但是外显子的数量和长度可以是任意的。
大多数基因识别算法分为两步:第一步,寻找可能的外显子;第二步,通过寻找一条拥有尽可能多的外显子的基因链,尽可能大地拼接一个基因。这条链必须遵循外显子出现在基因组序列中的顺序。外显子i在外显子j的前面的条件是i的末尾必须在j开头的前面。
本题的目标是,给定一组可能的外显子,找出一条拥有尽可能多的外显子链,拼接成一个基因。

输入

给出几组输入实例。每个实例的开头是基因组序列中可能的外显子数n(0 < n < 1000)。接着的n行,每行是一对整数,表示外显子在基因组序列中的起始和结束位置。假设基因组序列最长为50000。当一行是0时,表示输入结束。

输出

对于每个实例,找出最可能多的外显子链,输出链中的外显子,并占一行。假如有多条链,但外显子数相同,那么可以输出其中任意一条。

样例输入

6
340 500
220 470
100 300
880 943
525 556
612 776
0

样例输出

3 1 5 6 4
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 50;

struct node {
    int x;int y;
    int i;
    bool operator<(const node& p)const {
        return x < p.x;
    }
}wxz[maxn];

int n;
void solve() {
    for (int i = 1;i <= n;i++) {
        cin >> wxz[i].x >> wxz[i].y;
        wxz[i].i = i;
    }
    sort(wxz + 1, wxz + 1 + n);
    vector<node>ans;
    ans.push_back(wxz[1]);
    for (int i = 2;i <= n;i++) {
        struct node ni = ans.back();
        if (ni.y > wxz[i].y) {
            ans.pop_back();ans.push_back(wxz[i]);
        }
        else if (ni.y < wxz[i].x) {
            ans.push_back(wxz[i]);
        }
    }
    for (int i = 0;i < ans.size();i++) {
        cout << ans[i].i << " ";
    }
    cout << '\n';
}

int main() {
    while (cin >> n && n)
        solve();
}

1294: F005 主框架

题目描述

多纳先生是ACM(Agent on Computing of Mathematics,计算数学代理商)大型计算机的管理员。该代理商为一些公司承担在大型计算机上的计算工作,完成工作后获得报酬,因此大型计算机对这个代理商来说太重要了。多纳先生需要为这些在大型计算机上运行的作业安排顺序。一旦要运行某个作业,他就要检查运行该作业所需要的空闲资源。如果空闲资源足够的话,他就为该作业分配这些资源;否则就将该作业挂起,直至有足够的资源投入运行。
刚开始他并不熟悉这项工作,把事情搞得很乱。日积月累,他就胜任这项工作了。而且他还总结了一套规则:
(1)大型计算机有M个CPU和N大小的内存空间可供分配。

(2)对等待运行的作业有一个等待队列。可以假定这个队列足够长,能够存放所有等待运行的作业。

(3)假定作业Ji需要Ai个CPU和Bi的内存空间,在时间Ti到达等待队列,需要在时间Ui之前完成。成功运行后,代理商可以获得Vi()的报酬;如果能在规定的时间之前完成,则每小时还可以额外获得Wi()的奖金;如果工期拖延,则每小时赔偿Xi()。例如,假定一个作业的报酬是10,时限8小时,每拖欠一小时罚2。如果该作业在10小时完成,则代理商可以获得10-(10-8)*2=6。

(4)当一个作业开始后,就独占了分配给它的CPU和内存空间,不能同时再分配给其他作业。当该作业运行结束后,这些资源被释放。如果资源足够多,同时可以运行多个作业。

(5)为了最大限度地发挥大型计算机的计算能力,每个作业在开始运行后刚好一小时就完成。你可以假定每个作业的运行时间就是一小时。

(6)没有作业运行时,机器空闲,一直到一个作业进入作业等待队列。

(7)如果有多个作业进入作业等待队列,则报酬高的作业优先。可以假定这些作业的报酬都不相等。

(8)如果某个作业的空闲CPU或内存空间不能满足,它就是被挂起一小时,也不占用任何资源。一小时后,再次为该作业检查资源,而不需要考虑等待队列里的其他作业。如果资源仍不满足要求,那就继续挂起一小时,把资源分配给其他在等待队列里的作业。否则,该作业将独占CPU和存储空间并投入运行。

(9)当多个作业挂起时,采取先来先服务的原则。

使用这些规则,多纳先生把事情安排得井井有条。现在除了日常公务外,代理商要求他根据作业列表计算收入。给定某个时间F,计算出已经完成的作业和应该被完成的作业。对作业Ji,如果它的时限Ui>F并且仍未完成,就不需要统计收入。对已经完成的作业或Ui≤F的作业都要统计。如果工作没有完成,它不会给代理商带来报酬,但到这个时间F为止的罚款仍要计算。

他不会程序设计,又不想手工做,现在你帮助他解决这个问题。

输入

有多组测试例。每个测试例描述大型计算机的资源和作业列表,第一行是整数F(0≤F≤10000),表示时限。接下来的一行是三个整数M,N和L(M,N,L≥0),M是机器CPU的数量,N是存储空间的大小,L是作业等待队列中作业的数量。最多有10000个作业。
后面的L行是作业的信息。描述作业Ji的数据是7个整数:Ai,Bi,Ti,Ui,Vi,Wi,Xi。Ai和Bi(Ai,Bi≥0)指出了该作业对CPU和内存的需求。Ti和Ui表示作业的到达时间和时限(0≤Ti≤Ui)。Vi,Wi,Xi分别是工作的报酬、奖励和罚款。
一个空的测试例(F=0)表示输入结束,该测试点无需处理。

输出

根据作业列表计算总收入。对每个测试例,输出测试例编号,一个冒号,一个空格,然后是收入。
测试例之间有一个空行。
注意:对尚未投入运行的、且时限超过F的作业,不必统计。

样例输入

10
4 256 3
1 16 2 3 10 5 6
2 128 2 4 30 10 5
2 128 2 4 20 10 5
0

样例输出

Case 1: 74
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 20;

struct JOB {
    int a, b, t, u, v, w, x;
    bool ok;
    JOB(int a, int b, int t, int u, int v, int w, int x) :a(a), b(b), t(t), u(u), v(v), w(w), x(x), ok(false) {}
    bool operator<(const JOB& N)const {
        if (N.t == t)
            return v > N.v;
        return t < N.t;
    }
};
int ind = 1;
int f;
int m, n, l;
int mi, ni;
void solve() {
    cin >> m >> n >> l;
    vector<JOB>tot;
    for (int i = 0;i < l;i++) {
        int a, b, t, u, v, w, x;
        cin >> a >> b >> t >> u >> v >> w >> x;
        tot.push_back(JOB(a, b, t, u, v, w, x));
    }
    sort(tot.begin(), tot.end());
    int ans = 0;
    for (int i = 1;i <= f;i++) {
        mi = m;ni = n;
        for (int j = 0;j < l;j++) {
            if (tot[j].t >= i)
                break;
            if (tot[j].ok || mi < tot[j].a || ni < tot[j].b)
                continue;
            tot[j].ok = true;
            mi -= tot[j].a;
            ni -= tot[j].b;
            ans += tot[j].v;
            if (i > tot[j].u)
                ans -= (i - tot[j].u) * tot[j].x;
            else if (i < tot[j].u)
                ans += (tot[j].u - i) * tot[j].w;
        }
    }
    for (int i = 0;i < l;i++) {
        if (!tot[i].ok && tot[i].u <= f)
            ans -= (f - tot[i].u) * tot[i].x;
    }
    printf("Case %d: %d\n\n", ind, ans);
    ind++;
}

int main() {
    while (cin >> f && f)
        solve();

    return 0;
}

1295: F006 整数区间

题目描述

一个整数区间[a,b] (a < b),是一个从a到b连续整数的集合。
现在给你n个整数区间,编程找出一个集合R,使得n个集合中的每个集合都有2个整数出现在R中,并且这个集合R包含的整数个数最少。

输入

输入有多组数据,每组第一行包含整数n(1 <= n <= 10000),表示整数区间的个数。接下来n行,每行包含两个整数a和b(0 <= a < b <= 10000, a < b)。

输出

输出符合条件的集合R中元素的个数。

样例输入

4
3 6
2 4
0 2
4 7

样例输出

4
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 50;

int cnt[maxn];
int n;
int ck[maxn];
bool hasi[maxn];
void solve() {
    while (cin >> n) {
        fill(hasi, hasi + 10005, false);
        fill(ck, ck + n + 5, 0);
        fill(cnt, cnt + 10005, 0);
        if (!n)return;
        vector<pair<int, int>> v;
        for (int i = 0;i < n;i++) {
            int a, b;
            cin >> a >> b;
            v.push_back(make_pair(a, b));
            for (int j = a;j <= b;j++) {
                cnt[j]++;
            }
        }
        int ans = 0;
        while (true) {
            int mx = max_element(cnt, cnt + 10005) - cnt;
            // cout << mx << endl;
            if (cnt[mx] == 0)break;
            hasi[mx] = true;
            ans++;
            fill(cnt, cnt + 10005, 0);
            for (int i = 0;i < n;i++) {
                if (ck[i] == 2)continue;
                if (v[i].first <= mx && v[i].second >= mx) {
                    ck[i]++;
                }
                if (ck[i] == 2)continue;

                for (int j = v[i].first;j <= v[i].second;j++) {
                    if (hasi[j])
                        continue;
                    cnt[j]++;
                }
            }
        }
        cout << ans << endl;
    }
}

int main() {
    // int t;cin >> t;
    // while (t--)
    solve();

    return 0;
}

1296: F007 安装雷达

题目描述

我们假设海岸线是一条无限直线:以海岸线为界,陆地和海洋被分开,在海边分布着很多小岛。现在,我们在海岸线上安装雷达,每个雷达有固定的通讯范围(以d为半径的圆形区域),这样,海边的小岛就可以被某个雷达信号覆盖。
这里我们使用笛卡尔坐标系,定义海岸线为x轴,x轴上方是海洋,下方是陆地。给出分布在海边每个小岛的坐标位置和雷达信号能覆盖的范围d,你的任务是计算出最小需要安装的雷达数目,使得这些雷达信号能覆盖到所有海边的小岛。每个小岛的坐标格式为(x,y)。
如下图所示,给出第一个输入样例的坐标表示,这样在(-2,0),(1,0)上分别安装雷达就可以覆盖所有的小岛(p点),所以我们只需要安装2个雷达。

F007.jpg

输入

输入包含多组测试样例。每组测试第一行包含两个整数n(1<=n<=1000)和d,n表示小岛的数目,d表示雷达能覆盖的范围的半径。接下来n行,每行由整数x和y组成,表示n个小岛的坐标位置。每两组数据之间有一个空行。
输入0 0表示输入的结束。

输出

对于每一组输入,按照输出样例中的格式输出:包含输出序号和最少需要安装雷达的数目。如果找不到解决方案,即不能找到一种安装方案覆盖所有的小岛,输出”-1”。

样例输入

3 2
1 2
-3 1
2 1

1 2
0 2

0 0

样例输出

Case 1: 2
Case 2: 1
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

struct node {
    double x, y;
    node(double x, double y) :x(x), y(y) {}
    bool operator < (const node& a) const {
        return y < a.y;
    }
};
int n;
int d;
int ind;
void solve() {
    ind = 1;
    while (cin >> n >> d) {
        if (n == 0 && d == 0)return;
        bool f = true;
        vector<node> q;
        for (int i = 0;i < n;i++) {
            int x, y;cin >> x >> y;
            if (d < y)
                f = false;
            if (!f)continue;
            double ei = sqrt(1.0 * d * d - 1.0 * y * y);
            q.push_back(node{ x - ei,x + ei });
        }
        if (!f) {
            printf("Case %d: -1\n", ind);
            ind++;
            continue;
        }
        sort(q.begin(), q.end());
        int ans = 1;
        double yi = q[0].y;
        for (int i = 1;i < q.size();i++) {
            if (q[i].x <= yi) {
                continue;
            }
            else {
                ans++;
                yi = q[i].y;
            }
        }
        printf("Case %d: %d\n", ind, ans);
        ind++;
    }
}

int main() {
    // int t;cin >> t;
    // while (t--) 
    solve();


    return 0;
}

1297: F008 排队买饭

题目描述

周晓晓吃完中午饭后又觉得没吃饱,因此想要再去食堂买点饭,当她走进食堂发现已经有n个人排队了,她知道每个人买饭需要的时间。她想帮助大家尽快的买到饭,即让n个人的平均等待时间最小,周晓晓已经饿的无法想出办法,只想知道他们最小的平均等待时间是多少,你能帮助她吗?

输入

输入可能有多组,每组第一行为一个整数n。 第二行 n 个整数,第 i 个整数 Ti 表示第i个人的等待时间Ti。

输出

每组输出占一行,为每组最小的平均等待时间(输出结果精确到小数点后两位)。

样例输入

10 
56 12 1 99 1000 234 33 55 99 812

样例输出

532.00
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 20;
int a[maxn];

int n;
void solve() {
    for (int i = 0;i < n;i++)cin >> a[i];
    sort(a, a + n);
    int ans = 0;
    int tmp = 0;
    for (int i = 0;i < n;i++) {
        tmp += a[i];
        ans += tmp;
    }
    printf("%.2lf\n", 1.0 * ans / n);
}

int main() {
    while (cin >> n)
        solve();

    return 0;
}

1298: F009 放书

题目描述

周小小最近想为自己的图书室添置一个巨型书架,尽管它是如此的大,但它还是几乎瞬间就被各种各样的书塞满了。现在,只有书架的顶上还留有一点空间。
所有N(1<=N<=2000)把椅子都有一个确定的高度Hi(1<=Hi<=1000)。为了够到书架顶,周小小想像演杂技一般,将椅子一个一个的叠在一起,并上去把书架的空间补上。
显然,椅子叠的越多,就越不稳定,于是小小希望在够到书架顶的前提下,让椅子数量尽量少,作为聪明的你,一定能帮助他计算出这个最小数量吧。

输入

第1行: 2个用空格隔开的整数:N和B,表示有N把椅子和书架的高度;
第2行到N+1行: 第i+1行是1个整数:Hi,表示椅子的高度。
可能存在多组输入数据。

输出

输出1个整数,即最少要多少把椅子。(如果到不了顶端,输出-1)

样例输入

6 40
6
18
11
13
19
11

样例输出

3
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2010;
int h[maxn];

int n, b;
void solve() {
    for (int i = 0;i < n;i++)
        cin >> h[i];
    sort(h, h + n);
    int sum = 0, cnt = 0;
    for (int i = n - 1;i >= 0;i--) {
        sum += h[i];
        cnt++;
        if (sum >= b) {
            cout << cnt << endl;
            return;
        }
    }
    cout << -1 << endl;
}

int main() {
    while (cin >> n >> b)
        solve();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值