《算法竞赛-训练指南》第一章-1.16_LA 3177

来源:互联网 发布:php程序员必备书籍 编辑:程序博客网 时间:2024/05/24 05:50

这道题目很有意思。但是我就是错的非常离谱,就差拿着题解一句话一句话的去对照了,不,其实我已经对照了的。


首先说一下这个题目的意思,就是说有N个塔防的士兵,他们分别相邻,1和2和N相邻,2和1和3相邻。现在每个塔防的士兵要奖品,问题是你发的奖品使得每个相邻的士兵不具有相同的奖品。


这个刚开始一看,没思路,是一道非常难的题目。

看了题解,也就懂了。自己的智商不高,怪不了别人那。你可以这样的理解题意,其实刚开始的时候自己都已经推导出了部分,但是因为太麻烦也给放弃了,在真正比赛中,还是希望自己能够分类讨论,细心的研究最少半个小时以上。这个也是分类讨论的,但是你讨论的前提也是要得知道怎么样才能得到最优的分配。比如这道题目,作者就给出了很好的最优分配,就是两边的士兵尽量要一边拿尽量小的,而另一边拿尽量大的。这样才能得到最优,当偶数的时候,直接就是相邻两个数最大的和情况是最优的。而当是奇数的时候,发现,这个时候的规律是不满足的,但是不要着急,我们知道了答案的范围,无非是大于2个数的和小于三个数的最大和。而且相差的又不很大,那么随便一二分答案,就能出来结果了。但是,别着急,还有重要的你没有解决,那就是怎么样把自己的思想转化成程序实现,我想就算我知道了这个思路,也实现不了这个程序,因为,你根本就不能讲你的思想通过数据结构,算法转化成程序,这就是自己程序设计能力不高的原因。

而题目中是,分别找去了两个数组,数组的值代表了你所取的奖励编号的个数,这个为什么可以这样表示?是因为你每次都是尽量取左边,尽量取右边,不是胡乱的取,所以我的个数就能唯一代表我取的,虽然具体是几号不知道,但是题中也没有让求。(让求我们也可以推出来!!!就是弄个扫一遍数组的值就可以实现)。


好了,就说这么多吧。很有价值,但是还是看自己能不能好好的利用吧!

贴出代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <string>using namespace std;const int MAXN = 100000 + 11;int A[MAXN];int L[MAXN];int R[MAXN];int N;int max(int a, int b){return a > b ? a : b;}bool check(int key){int x = A[1]; // 这代表着将礼物分成两片,第一片是A[1]为左边, int y = key - A[1]; //第二片为key - A[1]为右边;L[1] = x;R[1] = 0; for (int i = 2; i <= N; i++){if (i % 2 == 0) //如果是偶数的情况下,极力的向左靠近 {L[i] = min(x - L[i - 1], A[i]);R[i] = A[i] - L[i];}else //如果是奇数的情况下,极力的向右靠近 {R[i] = min(y - R[i - 1], A[i]);L[i] = A[i] - R[i];}}return L[N] == 0;}int main(){while (scanf("%d", &N) != EOF){if (N == 0){break;}for (int i = 1; i <= N; i++){scanf("%d", &A[i]);}if (N == 1){printf("%d\n", A[1]);continue;}int MAX1 = -1;int MAX2 = -1;A[N + 1] = A[1];for (int i = 1; i <= N; i++){MAX1 = max(MAX1, A[i] + A[i + 1]);}for (int i = 1; i < N - 1; i++){MAX2 = max(MAX2, A[i] + A[i + 1] + A[i + 2]);//MAX2 = max(MAX2, A[i] * 3); }if (N % 2 == 0) //偶数的情况较为简单. {printf("%d\n", MAX1);}else{int left = MAX1;int right = MAX2;while (left < right) // 找最小值 {int mid = left + (right - left) / 2;if (check(mid)){right = mid;}else{left = mid + 1;}}printf("%d\n", right);}}//system("pause");return 0;}


原创粉丝点击