算法设计与分析入门篇----贪心法2

来源:互联网 发布:淘宝客怎么退出 编辑:程序博客网 时间:2024/06/02 02:11

正在网易云课堂学习王宏志老师的算法设计与分析入门篇课程视频,将学习中的作业问题发上来与大家一同讨论。这篇是对第五周的作业第二题个人的一些思路,希望与大家一同学习。

夺冠热门
题目内容:
n 个人将会进行一轮比赛,决出 1 到 n 名。(没有并列)
这轮比赛开始之前,每个人已经有一个初始分数(可能有并列)。在这轮比赛结束后,第 i 名的人将获得 n-i+1 分。
问这轮比赛结束后,有望得到第一的人会有多少人(并列第一也算第一)。

输入格式:
第一行一个整数 n(0 <= n <= 1000),表示人数。
接下来的一行,每行一个正整数 ai(0 <= ai <= 1000),表示每个人的初始分数。

输出格式:
输出一行一个整数 n,表示可能夺冠的人数。

输入样例:
5
3 4 5 6 9

输出样例:
3
Hint:
9 分的那个人至少也会得到 1 分因而是 10 分。
而 5 + 5 = 10,因此 5 分的人也是有望夺冠的。
再低就不行了。
时间限制:2000ms内存限制:128000kb

#include <iostream>#include <vector>#include <iomanip> #include <algorithm>#include <functional>using namespace std;float max(vector<float> p){    float max = p[0] + 1;    for (int i = 1; i < p.size(); i++){        p[i] = p[i] + i + 1;        if (max < p[i])            max = p[i];    }    return max;}int main(){    int n;    while (cin >> n){        if (n == 0){            cout << 0 << "\r\n";            system("pause");        }        vector<float> p(n);        for (int i = 0; i < n; i++){            cin >> p[i];        }        sort(p.begin(), p.end(), greater<float>());        //可能得第一的选手初始的最低成绩        float zuidi = max(p) - n;        //可能得第一的人数        int mayfirst = 1;        while (mayfirst < n && p[mayfirst] >= zuidi){            mayfirst++;        }        cout << mayfirst << "\r\n";    }    system("pause");}

个人认为没有问题,但就过了一个测试用例。
正确性证明:
n个人按分数从大到小排列
k1 k2 k3 …… kn,分别加上1 2 3 ……. n
得到sum1 sum2 sum3 ………sumn,求出最大值为summ,设min=summ-n。
//min为可能的第一的最低基础分,下面会证明。
因为summ = km+m >=kn+n,所以min =summ-n>=0.
则对于ki>=min就有,
k1 k2 k3 ………ki……. kn ,仅将kn与ki的第二轮得分互换即ki+n,kn+i。
由于ki>=min,所以ki+n>=min+n=summ,又因为summ为原得分情况sum1 sum2 sum3 ………sumn中最大值,而更改得分的仅为ki与kn,所以summ依旧为更改后分情况sum1 sum2 sum3 ………sumn中除sumi外最大值(sumn变小,不影响)。
则sumi>=任意选手的总分,则第i名选手至少为并列第一。

对于ki < min的有,
k1 k2 k3 ………ki……. kn ,将kn与ki的第二轮得分互换后,sumi依旧小于summ。而如果想要将summ变小,则km要加上一个小于m的数设为m1。但对于原来加上m1的数km1而言km1>=km,交换后km1+m>=km+m>ki+n。sumi依旧不是最大的,并永远没可能是最大的。

所以可能为冠军的选手的初始分数一定大于等于min。
并且对于任何初试分数大于等于min的选手就有可能得冠军。

0 0
原创粉丝点击