ccnu_2016_summer_week1(2)_贪心

暑期集训的第三套题。简单贪心。

1.发工资咯:)

作为杭电的老师,最盼望的日子就是每月的8号了,因为这一天是发工资的日子,养家糊口就靠它了,呵呵
但是对于学校财务处的工作人员来说,这一天则是很忙碌的一天,财务处的小胡老师最近就在考虑一个问题:如果每个老师的工资额都知道,最少需要准备多少张人民币,才能在给每位老师发工资的时候都不用老师找零呢?
这里假设老师的工资都是正整数,单位元,人民币一共有100元、50元、10元、5元、2元和1元六种。

Input

输入数据包含多个测试实例,每个测试实例的第一行是一个整数n(n<100),表示老师的人数,然后是n个老师的工资。
n=0表示输入的结束,不做处理。

Output

对于每个测试实例输出一个整数x,表示至少需要准备的人民币张数。每个输出占一行。

Sample Input

3
1 2 3
0

Sample Output

4

【题目大意】
用一些面额的钱给n个老师发工资,问需要的最少的钱张数。
【解法】
不断取整取余即可。
【AC代码】

#include

int con(int money){
    int a[10] = {100, 50, 10, 5, 2, 1};       //定义一个存放单张人民币金额的数组
    int Time = 0, term, i;              //Time是张数,赋初始值为0
    for(i = 0; i < 6; i++){
        term = money / a[i];               //计算需要当前金额票面的张数
        Time += term;                    //记下张数,并累加
        money -= term*a[i];             //去掉当前金额的整数倍
    }

    return Time;                   //将张数返回
}

int main (){
    int N, sum, num, term;
    while(scanf("%d",&N) != EOF && N){
        sum = 0;                                    //总张数赋初始值为0
        while(N--){
            scanf("%d", &num);                     //读取当前老师的金额
            term = con(num);                    //计算当前老师至少需要的人民币张数
            sum += term;                           //张数累加
        }

        printf("%d\n",sum);
    }
    return 0;
}

2.Saving HDU

Problem Description

话说上回讲到海东集团面临内外交困,公司的元老也只剩下XHD夫妇二人了。显然,作为多年拼搏的商人,XHD不会坐以待毙的。
一天,当他正在苦思冥想解困良策的时候,突然想到了自己的传家宝,那是公司成立的时候,父亲作为贺礼送来的一个锦囊,徐父当时交代,不到万不得已的时候,不要打开它。“现在不正是最需要的时候吗?”,一边想,XHD一边找到了这个精心保管的锦囊,打开一看,里面只有一句话“杭城北麓千人洞有宝”。
二话不说,XHD拿起一个大口袋就出发了,这个千人洞他是知道的,小的时候,爸爸曾经带他来过这个隐蔽的路口,并告诉他,这是千人洞。他现在才明白爸爸当初这句话的含义。
尽管有点印象,XHD还是花了很大的精力才找到这个异常隐蔽的洞口,走进一看,几乎惊呆了,真的是眼花缭乱!不过尽管宝贝的种类不少,但是每种宝贝的量并不多,当然,每种宝贝单位体积的价格也不一样,为了挽救HDU,现在请你帮忙尽快计算出来XHD最多能带回多少价值的宝贝?(假设宝贝可以分割,分割后的价值和对应的体积成正比)

Input

输入包含多个测试实例,每个实例的第一行是两个整数v和n(v,n<100),分别表示口袋的容量和宝贝的种类,接着的n行每行包含2个整数pi和mi(0

#include 
#include 
#include 
#include 
#include 

using namespace std;

struct Point{
    int pi;                     ///单价
    int mi;                     ///体积
}P[120];

bool cmp(Point a, Point b){
    return a.pi > b.pi;
}

int main(){
    int v, n;
    while(scanf("%d", &v) != EOF && v){                         ///口袋的容量
        scanf("%d", &n);                                        ///宝贝的种类
        for(int i = 0; i < n; i++){
            scanf("%d%d", &P[i].pi, &P[i].mi);                  ///单价和体积
        }
        sort(P, P + n, cmp);
//        printf("\n");
//        for(int i = 0; i < n; i++){
//            printf("单价是%d, 体积是%d\n", P[i].pi, P[i].mi);
//        }
//        printf("\n");
        int ans = 0;
        for(int i = 0; i < n; i++){
            if(v >= P[i].mi){
                ans += P[i].mi * P[i].pi;
//                printf("ans = %d\n", ans);
                v -= P[i].mi;
            }
            else{
                ans += v * P[i].pi;
//                printf("ans = %d\n", ans);
                break;
            }

        }
        printf("%d\n", ans);
    }
    return 0;
}

3.Crossing River

Description
A group of N people wishes to go across a river with only one boat, which can at most carry two persons. Therefore some sort of shuttle arrangement must be arranged in order to row the boat back and forth so that all people may cross. Each person has a different rowing speed; the speed of a couple is determined by the speed of the slower one. Your job is to determine a strategy that minimizes the time for these people to get across.

Input
The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. The first line of each case contains N, and the second line contains N integers giving the time for each people to cross the river. Each case is preceded by a blank line. There won’t be more than 1000 people and nobody takes more than 100 seconds to cross.

Output
For each test case, print a line containing the total number of seconds required for all the N people to cross the river.

Sample Input

1
4
1 2 5 10

Sample Output

17

【题目大意】
给定n个人,在岸的一边。目的是使所有人到达岸的对面。这个船每次最多只能坐两个人。每个人都有一个特定的过河时间。两个人乘船时。过河的时间由时间较长的人决定。
求最短的过河时间。
【解法】
人少的时间,1,2,3人的时候可以显然得出。
如果是4个人以及以上的话:
为了让总时间最短,由于每次摆渡回来需要一个人开船,所以可以考虑每次都让开船最快的人来运船。——-策略1
但是策略1有一个缺点,就是最慢的两个人都需要花时间过去。所以可以考虑让最慢的两个人一堂过去。—–策略2
策略1将最慢的两个人运过去的时间是p[n] + p[n - 1] + 2 * p[1]
策略2将最慢的两个人运过去的时间是p[1] + p[n] + 2 * p[2]
为了让时间最短。取两种策略所花时间的较小值。
【AC代码】

#include 
#include 
#include 
#include 
#include 

using namespace std;

int people[1010];

int main(){
    int T, n;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d", &people[i]);
        }
        sort(people + 1, people + 1 + n);
        int ans = 0;
        while(n){
            if(n == 1){
                ans += people[1];
                n -= 1;
            }
            else if(n == 2){
                ans += people[2];
                n -= 2;
            }
            else if(n == 3){
                ans += (people[1] + people[2] + people[3]);
                n -= 3;
            }
            else{
                ans += min( (people[n] + people[n - 1] + 2 * people[1]), (people[1] + people[n] + 2 * people[2]) );
                n -= 2;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}

4.今年暑假不AC

“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%…”

确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。

12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0

Sample Output

5

【题目大意】
给出几个电视节目播出的时间段。求最多可以观看几个完整的电视节目。
【解法】
经典贪心题。
为了观看更多的节目,应该优先观看当前最先结束的节目。
所以按照电视节目的结束时间升序排序,
依次选取不冲突的节目即可。
【AC代码】

#include

int main (){
    int N, star[105], end[105], temp, end_min, count, i, j;
    while(scanf("%d", &N) != EOF && N){
        for(i = 0; i < N; i++){
            scanf("%d %d", &star[i], &end[i]);
        }
        for(i = 0; i < N; i++){
            for(j = i + 1; j < N; j++){
                if(end[j] < end[i]){
                    temp = end[j];                         //结束时间升序排列
                    end[j] = end[i];
                    end[i] = temp;

                    temp = star[j];                         //对应的开始时间也换位置,保持一致性
                    star[j] = star[i];
                    star[i] = temp;
                }
            }
        }

        end_min = end[0];                   //以第一个结束时间为初始装态
        count = 1;                          //计数器初始化为1
        for(i = 0; i < N; i++){
            if(star[i] >= end_min){
                end_min = end[i];              //结束时间更新
                count++;                         //计数器加一
            }
        }
        printf("%d\n", count);              //输出
    }

    return 0;
}

5.Hero
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4528 Accepted Submission(s): 1983

Problem Description

When playing DotA with god-like rivals and pig-like team members, you have to face an embarrassing situation: All your teammates are killed, and you have to fight 1vN.

There are two key attributes for the heroes in the game, health point (HP) and damage per shot (DPS). Your hero has almost infinite HP, but only 1 DPS.

To simplify the problem, we assume the game is turn-based, but not real-time. In each round, you can choose one enemy hero to attack, and his HP will decrease by 1. While at the same time, all the lived enemy heroes will attack you, and your HP will decrease by the sum of their DPS. If one hero’s HP fall equal to (or below) zero, he will die after this round, and cannot attack you in the following rounds.

Although your hero is undefeated, you want to choose best strategy to kill all the enemy heroes with minimum HP loss.

Input

The first line of each test case contains the number of enemy heroes N (1 <= N <= 20). Then N lines followed, each contains two integers DPSi and HPi, which are the DPS and HP for each hero. (1 <= DPSi, HPi <= 1000)

Output

Output one line for each test, indicates the minimum HP loss.

Sample Input

1
10 2
2
100 1
1 100

Sample Output

20
201

【题目大意】
你现在在dota中,假设你有无限滴血。
现在你面前有N个敌人。这N个敌人都有两个属性。血量以及攻击力。
每个没死的敌人在每一秒都会给你带来等同于他的攻击力的伤害值。
求打死所有敌人时受到的最小的总伤害值。
【解法】
优先攻打血少并且攻击力高的。所以按照DPS/HP降序排序。
【AC代码】

#include 
#include 
#include 
#include 
#include 

using namespace std;

struct Point{
    int DPS;
    int HP;
}P[1010];

bool cmp(Point a, Point b){
    return (1.0 * a.DPS / a.HP ) > (1.0 * b.DPS / b.HP );
}

int main(){
    int N;
    while(scanf("%d", &N) != EOF){
        for(int i = 0; i < N; i++){
            scanf("%d%d", &P[i].DPS, &P[i].HP);
        }
        sort(P, P + N, cmp);
        int ans = 0;
        int time = 0;
        for(int i = 0; i < N; i++){
            ans += (P[i].HP + time) * P[i].DPS;
            time += P[i].HP;
        }
        printf("%d\n", ans);
    }

    return 0;
}

6.Subsequence
Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 12230
Accepted: 5117

Description
A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.

Input
The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.

Output
For each the case the program has to print the result on separate line of the output file.if no answer, print 0.

Sample Input

2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5

Sample Output

2
3

【题目大意】
找出一个数字序列中的一个最短的连续子序列,使得这串连续子序列的和大于等于一给定的值S。
输出,最短的序列长度。
【解法】
尺取法。
只要当前和小于S就向后加。
当前和大于等于S就更新ans,然后丢弃前面的数。
【AC代码】

#include 
#include 
#include 
#include 

using namespace std;

int a[100005];

int main(){
    int T, N, S;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &N, &S);
        for(int i = 0; i < N; i++){
            scanf("%d", &a[i]);
        }
        int l = 0, r = 0;
        int sum = 0;
        int ans = 0x3fffffff;
        int mark = 0;
        for(;;){
            while(r < N && sum < S){
                sum += a[r++];
            }
            if(sum < S){
                break;
            }
            ans = min(ans, r - l);
            sum -= a[l++];
        }
        if(ans != 0x3fffffff){
            printf("%d\n", ans);
        }
        else{
            printf("0\n");
        }
    }

    return 0;
}

你可能感兴趣的:(2016暑期集训,贪心)