@共同富裕
描述
给定一个数组A1, A2, … AN,每次操作可以从中选定一个元素Ai,把除了Ai之外的所有元素都加1。
问最少几次操作可以实现“共同富裕”,即数组中所有元素都相等。
例如对于[1, 1, 1, 2, 3]经过3步:[1, 1, 1, 2, 3] -> [2, 2, 2, 3, 3] -> [3, 3, 3, 3, 4] -> [4, 4, 4, 4, 4]。
输入
第一行包含一个整数N。(1 ≤ N ≤ 100000)
以下N行包含N个整数A1, A2, … AN。 (1 ≤ Ai ≤ 100000)
输出
最小的操作数
样例输入
5
1
1
1
2
3
样例输出
3
GCC
#include <stdio.h>
#include <stdlib.h>
const int MAXN = 100000 + 10;
int num[MAXN];
int comp(const void *a, const void *b){
return (*(int *)a - *(int *)b); //由小到大排序,return *(int *)b - *(int *)a; 为由大到小排序
}
int main(int argc, char** argv)
{
int n;
while (scanf("%d", &n) != EOF)/*EOF:EOF是一个计算机术语,为End Of File的缩写,在操作系统中表示资料源无更多的资料可读取。资料源通常称为档案或串流。通常在文本的最后存在此字符表示资料结束。*/
{
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
}
qsort(num,n,sizeof(num[0]),comp);//数列由大到小排列
long long ans = 0;
for(int i=n-1; i>0; --i)
{
ans += num[i] - num[0];
}
printf("%lld\n", ans );
}
return 0;
}
#include <cstdio>
#include <cstdlib>
const int MAXN = 100000;
int num[MAXN];
int cmp(const void *a, const void *b){
return (*(int *)a - *(int *)b);
}
int main(){
int n;
while(scanf("%d", &n) != EOF){
for(int i=0; i<n; ++i){
scanf("%d", &num[i]);
}
qsort(num, n, sizeof(num[0]), cmp);
long long ans = 0;
for(int i=n-1; i>0; --i){
ans += num[i] - num[0];
}
printf("%lld\n", ans );
}
return 0;
}
EOF 函数编辑
返回一个数值(整数类型Integer),它包含布尔值Boolean值True,表明已经到达为Random(Open语句方法)或顺序Input (Open 语句方法)打开的文件的结尾。
语法
EOF(filenumber)
必要的filenumber参数是一个Integer,包含任何有效的文件号。
说明
EOF (End Of File)
使用EOF是为了避免因试图在文件结尾处进行输入而产生的错误。
直到到达文件的结尾,EOF函数都返回False。对于为访问Random或Binary而打开的文件,直到最后一次执行的Get语句无法读出完整的记录时,EOF都返回False。
贪心算法转自此处 详情点击了解
一、概念
- 贪心法(Greedy Algorithm)定义
求解最优化问题的算法通常需要经过一系列的步骤,在每个步骤都面临多种选择;
贪心法就是这样的算法:它在每个决策点作出在当时看来最佳的选择,即总是遵循某种规则,做出局部最优的选择,以推导出全局最优解(局部最优解->全局最优解)
-
对贪心法的深入理解
(1)原理:一种启发式策略,在每个决策点作出在当时看来最佳的选择
(2)求解最优化问题的两个关键要素:贪心选择性质+最优子结构
①贪心选择性质:进行选择时,直接做出在当前问题中看来最优的选择,而不必考虑子问题的解;
②最优子结构:如果一个问题的最优解包含其子问题的最优解,则称此问题具有最优子结构性质
(3)解题关键:贪心策略的选择
贪心算法不是对所有问题都能得到整体最优解的,因此选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
(4)一般步骤:
①建立数学模型来描述最优化问题;
②把求解的最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解;
③证明做出贪心选择后:
1°原问题总是存在全局最优解,即贪心选择始终安全;2°剩余子问题的局部最优解与贪心选择组合,即可得到原问题的全局最优解。
并完成2° -
贪心法与动态规划
最优解问题大部分都可以拆分成一个个的子问题, 把解空间的遍历视作对子问题树的遍历, 则以某种形式对树整个的遍历一遍就可以求出最优解, 大部分情况下这是不可行的。 贪心算法和动态规划本质上是对子问题树的一种修剪, 两种算法要求问题都具有的一个性质就是子问题最优性 (组成最优解的每一个子问题的解,对于这个子问题本身肯定也是最优的)。 动态规划方法代表了这一类问题的一般解法, 我们自底向上构造子问题的解,对每一个子树的根, 求出下面每一个叶子的值,并且以其中的最优值作为自身的值, 其它的值舍弃。 而贪心算法是动态规划方法的一个特例, 可以证明每一个子树的根的值不取决于下面叶子的值, 而只取决于当前问题的状况。 换句话说,不需要知道一个节点所有子树的情况, 就可以求出这个节点的值。 由于贪心算法的这个特性, 它对解空间树的遍历不需要自底向上, 而只需要自根开始,选择最优的路, 一直走到底就可以了。
对于这道题
思路
1.排序
2.稳定最大的数,其他数增加
1 1 1 2 3
2 2 2 3 3
3 3 3 3 4
4 4 4 4 4
需要三步就可以完成了
1 2 3 4 5
2 3 4 5 5
3 4 5 6 5
4 5 6 6 6
5 6 7 6 7
6 7 8 7 7
7 8 8 8 8
8 9 9 9 8
9 10 10 9 9
10 11 10 10 10
11 11 11 11 11
需要10步
最后一位5稳定了4次 =5-1
倒数第二位4稳定了3次=4-1
倒数第三位3稳定了2次=3-1
倒数第四位2稳定了1次=2-1
所以得出了一个结论
操作数=(a[n]-a[0])+(a[n-1]-a[0])+…+(a[1]-a[0])
qsort
中文名 | qsort |
---|---|
头文件 | stdlib.h |
用 法 | voidqsort(void *base,int nelem,int width,int (*fcmp)(constvoid *,const void *)); |
参数 | 数组首地址 ,数组中待排序元素数量,各元素的占用空间大小,指向函数的指针,用于确定排序的顺序 |
用法
使用qsort()排序并用 bsearch()搜索是一个比较常用的组合,使用方便快捷。
qsort 的函数原型是
voidQuickSort(int a[],int numsize)//a是整形数组,numsize是元素个数
{
int i=0,j=numsize-1;
int val=a[0];//指定参考值val大小
if(numsize>1)//确保数组长度至少为2,否则无需排序
{
while(i<j)//循环结束条件
{
for(;j>i;j--)//从后向前搜索比val小的元素,找到后填到a[i]中并跳出循环
if(a[j]<val)
{
a[i]=a[j];
break;
}
for(;i<j;i++)//从前往后搜索比val大的元素,找到后填到a[j]中并跳出循环
if(a[i]>val)
{
a[j]=a[i];
break;
}
}
a[i]=val;//将保存在val中的数放到a[i]中
QuickSort(a,i);//递归,对前i个数排序
QuickSort(a+i+1,numsize-1-i);//对i+1到numsize这numsize-1-i个数排序
}
}
其中base是排序的一个集合数组,num是这个数组元素的个数,width是一个元素的大小,comp是一个比较函数。
比如:对一个长为1000的数组进行排序时,int a[1000]; 那么base应为a,num应为 1000,width应为 sizeof(int),comp函数随自己的命名。
qsort(a,1000,sizeof(int),comp);
其中comp函数应写为:
int comp(const void *a, const void *b)
{
return (*(int *)a - *(int *)b); //由小到大排序,return *(int *)b - *(int *)a; 为由大到小排序
}
上面是由小到大排序,return *(int *)b - *(int *)a; 为由大到小排序。