【ACM学习周记03】贪心算法(03)

一.题目解法与WA分析

1.题G.巧妙解法

题目描述:
有400个房间,门是对着的:
题图
现在要将若干个房间中的椅子搬运。
由于狭道太窄了,一次只能搬运一张桌子。搬运一张桌子需要10分钟,而且情况如下:
题图
求最短搬运时间。

样例输入:

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

输出:

10
20
30

思路分析:
这里运用到了一个非常巧妙的方法。把1、2房间看成一个走廊,3、4房间看成一个走廊…
一共200个走廊。我们只记下走过次数最多的走廊(即是轮数)乘10即得。
实现代码:

#include <iostream>

using namespace std;

int main(){  
    int i, m, n, k, j;
    cin >> m;
    while(m--){
	    cin >> j;
        int zoulang[200] = { 0 };
        //不可写成zoulang[200] = { 0 },否则只是对第201个元素赋值
	    while(j--){
            cin >> n >> k;
		    if(n > k) { i = n; n = k; k = i; }
            for(i = (n + 1) / 2; i <= (k + 1) / 2; i++) zoulang[i]++;		               
	    }
        int count = 0;
	    for(i = 0; i < 200; i++)
            if(count < zoulang[i])
                count = zoulang[i];
	    cout << count * 10 << endl;
   }
   return 0;
}

2.J题WA分析

题目描述:

小明做作业,一共有 n 门。
每门有期限,超限没学分。
学分各不同,期限会重叠。
实在做不完,最低减多少分?

样例输入:
输入t组,然后输入作业数,接下来是作业时间n([0, n])和学分。

3
3
3 3 3
10 5 1
3
1 3 1
6 2 3
7
1 4 6 4 2 4 3
3 2 1 7 6 5 4

输出:
最低减分。

0
3
5

WA分析:
WA大意:因为既有时间限制,又有学分权重。这时把时间作为第一权重降序,学分作为第二权重升序。然后遍历。
这样做是不行的,因为有时候出现时间短学分少却在权重比较中“压没”时间长学分多的。
于是,可以尝试向struct添加一个flag,表示有没有被遍历选中。这样,再遇到不得不扣学分项时,可以看看前面有没有没选过而且扣得少的来抵押。
代码实现:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>

using namespace std;

struct node{
    int t;
    int s;
    bool flag;
}pool[10010];

bool cmp(node a, node b){
    if(a.t != b.t) return a.t < b.t;
    else return a.s > b.s;
}

int main() {
    int i, t, n, s, count;
    cin >> t;
    while(t--){
        cin >> s;
        for (i = 0; i < s; i++) cin >> pool[i].t;
        for (i = 0; i < s; i++) { cin >> pool[i].s; pool[i].flag = false; }
        sort(pool, pool + s, cmp);
        int sum = 0, k = 1;
        for (i = 0; i < s; i++){
            if(pool[i].t >= k){ k++;continue; }
            int pos = i, tmp = pool[i].s;
            for (n = 0; n < i; n++){
                if(pool[n].s < tmp && !pool[n].flag){
                    tmp = pool[n].s;
                    pos = n;
                }
            }
            sum += tmp;
            pool[pos].flag = true;
        }
        cout << sum << endl;
    }
    return 0;
}

3.T题WA分析

题目大意:

整数列组[a, b], a 和 b 啥的都是整数。
找出两个不同数,每个区间都含有。
所以最少几个数。

WA分析:
WA解法:设置区间块为第一个区间首位和末位。如果重叠,首位不动,末位到第二个区间末位且自增2。
正确解法:因为是两个整数,所以我们创建一个“区间块”[m, n],其中m n都是整数,且m n相邻。这是我们只要找到区间重合部分的“区间块”即可。
设置计数器初始值是1,区间块初始为第一个区间末二位。
如果没有重叠,即“区间和”是0,则自增2,且区间块和蹦到下一个区间最后;
如果重叠一个数,即区间块2为半个,则自增一蹦区间和;
如果重叠两个,不增,区间块蹦。
代码实现:

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

struct node
{
    int a, b;
} pool[10010];

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

int main()
{
    int n, i, a_axis, b_axis, count;
    while (scanf("%d", &n) != EOF){
        count = 2;
        for (i = 0; i < n; i++)
            cin >> pool[i].a >> pool[i].b;
        sort(pool, pool + n, cmp);
        a_axis = pool[0].b - 1;
        b_axis = pool[0].b;
        for(i = 1; i < n; i++){
            if(pool[i].b >= b_axis && pool[i].a <= a_axis) continue;
            if (pool[i].a > b_axis){
                a_axis = pool[i].b - 1;
                b_axis = pool[i].b;
                count += 2;
            }else{
                a_axis = b_axis;
                b_axis = pool[i].b;
                count++;
            }
        }
        cout << count << endl;
    }
    return 0;
}

二.总结

这周学的不算多,主要以做题为主。在做题过程中发现了许多问题可以用极其简单的方法去做,有些题目需要考虑多种情况。在遇到这些题目时,只是看是不可以的,需要动手在纸上画画写写才能得出算法。
这周打CF的感觉和打OpenJudge、vjudge都不一样。CF比vjudge难了一些,因为算法不只局限于贪心,相比OpenJudge更是天上和地下的差别。以后要多在CF训练场训练。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值