Java教程

贪心

本文主要是介绍贪心,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1536. 均分纸牌

有NN堆纸牌,编号分别为 1,2,…,N。

每堆上有若干张,但纸牌总数必为 N 的倍数。

可以在任一堆上取若干张纸牌,然后移动。

移牌规则为:在编号为 1 的堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N−1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

例如 N=4 堆纸牌数分别为:(9,8,17,6)

移动 3 次可达到目的:

  1. 从第三堆取四张牌放入第四堆,各堆纸牌数量变为:(9,8,13,10)。
  2. 从第三堆取三张牌放入第二堆,各堆纸牌数量变为:(9,11,10,10)。
  3. 从第二堆取一张牌放入第一堆,各堆纸牌数量变为:(10,10,10,10)。

输入格式

第一行包含整数 N。

第二行包含 N 个整数,A1,A2,…,AN 表示各堆的纸牌数量。

输出格式

输出使得所有堆的纸牌数量都相等所需的最少移动次数。

数据范围

1≤N≤100
1≤Ai≤10000

输入样例:

4
9 8 17 6

输出样例:

3

分析:

这是一个展开的传递题,最左面的只能向最右边的传递,最右边的只能向最左面传递,而其他堆可以向两侧传递。显然,相邻的两堆纸牌传递两次及以上,是浪费的行为。所以,我们保证相邻两堆纸牌之间只会传递一次,要么左边传递给右边,要么右边传递给左端,而这个过程只会进行n-1次就可以让每堆纸牌数量达到平均值。

假定我们从左向右传递,a[i]与a[i + 1]之间进行传递,如果a[i]大于平均值,将a[i]多的部分分给a[i+1],如果a[i]小于平均值,就让a[i+1]分给a[i]。到了最后一堆的时候,一定达到了平均情况。

我们发现,i影响的是i的下一堆,我们主是将下一堆的数量标记好就可以了,产生影响的时候,计数,这是产生了传递的次数。

代码:

 1 #include <cstdio>
 2 
 3 using namespace std;
 4 
 5 const int N = 110;
 6 
 7 int n;
 8 int a[N];
 9 
10 int main()
11 {
12     scanf("%d", &n);
13     int ave;
14     for (int i = 1; i <= n; i ++ )
15     {
16         scanf("%d", &a[i]);
17         ave += a[i];
18     }
19     
20     ave /= n;
21     
22     for (int i = 1; i <= n; i ++ )
23     {
24         a[i] -= ave;
25     }
26     
27     int ans = 0;
28     for (int i = 1; i < n; i ++ )
29     {
30         if (a[i] != 0) a[i + 1] += a[i], ans ++;
31     }
32     
33     printf("%d\n", ans);
34     
35     return 0;
36 }
View Code

122. 糖果传递 

题目:

有 n 个小朋友坐成一圈,每人有 a[i] 个糖果。

每人只能给左右两人传递糖果。

每人每次传递一个糖果代价为 1。

求使所有人获得均等糖果的最小代价。

输入格式

第一行输入一个正整数 n,表示小朋友的个数。

接下来 n 行,每行一个整数 a[i],表示第 i个小朋友初始得到的糖果的颗数。

输出格式

输出一个整数,表示最小代价。

数据范围

1≤n≤1000000,
0≤a[i]≤2×109,
数据保证一定有解。

输入样例:

4
1
2
5
4

输出样例:

4

分析:

设x为前一个小朋有需要向后一个小朋友传递的糖果数,下面我们将题目进行转化

 

 

【我也搞不清要不要裂开,似乎是需要裂开的,这样才能像仓库选址,因为仓库选址本身就是在一条直线上的】在众多x中,因为他们自己的糖果数不同,所以他们相互传递的糖果数也不同,所以会出现x是正数、负数、和0.我们找到一个位置,这里的a的右边是负数,左边是正数或0。可以将这个点拆开,变成一条链。这个点表示,需要向左边分配0个或多个糖果,也也要向右边分配糖果。
再结合前面我们转化的关系, 这样我们会发现,我们要让`|xn - S1|, |xn - S2|, |xn - s3|, ...., |xn - Sn|`最小,这就是需要先排个序,然后在中间位置坐标的点选择建立仓库,然后计算最短距离之和。就变成了仓库选址模型了。

 这样就将问题转化为了仓库选址问题了。

 

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 typedef long long ll;
 9 
10 const int N = 1000010;
11 
12 int n;
13 ll a[N];
14 ll s[N];
15 
16 int main()
17 {
18     scanf("%d", &n);
19     ll ave = 0;
20     for (int i = 1; i <= n; i ++ )
21     {
22         scanf("%lld", &a[i]);
23         ave += a[i];
24     }
25     ave /= n;
26     
27     for (int i = 1; i <= n; i ++ )
28     {
29         s[i] = s[i - 1] + ave - a[i];
30     }
31     
32     sort(s + 1, s + 1 + n);
33     // nth_element(s + 1, s + n / 2, s + n);
34     ll ans = 0;
35     for (int i = 1; i <= n; i ++ )
36         ans += abs(s[i] - s[(n + 1) / 2]);
37     printf("%lld\n", ans);
38     
39     return 0;
40 }
View Code

 

这篇关于贪心的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!