UVA1335-- Beijing Guards

题意:有n个人围成一个圈,其中第i个人想要ri个不同的礼物。求最少需要多少种礼物,使得相邻的人的礼物都不相同。


思路:这是大白上面的一道贪心题目。想法挺好的。

首先如果n为偶数时,只要找出相邻两个人的r值最大,就是所需的最少的礼物数量。如果为奇数时,那情况就不一样了,因为当第1个和第n个都是奇数,按照上面的方法,他们的礼物种类是一样的,就不符合题意。那么我们可以按照第一个人所需要的礼物数量为基准划分区间。假设最坏情况下的礼物总数为R = max(ri) * 3,所以区间划分为【1,r1】,【r1 + 1,R】。所以只要记录每个人在这两个区间内取了几个,分别用front[i],back[i]表示。最后在判断是否符合,也就是第n个人是否在【1,r1】内取礼物。注意特判n == 1时的情况。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 100010;

int arr[MAXN], front[MAXN], back[MAXN];
int n;

int judge(int num) {
    int x = arr[1], y = num - arr[1];
    front[1] = x;
    back[1] = 0;
    for (int i = 2; i <= n; i++) {
        if (i % 2 == 1) {
            back[i] = min(y - back[i - 1], arr[i]); //尽量往后取
            front[i] = arr[i] - back[i]; 
        } 
        else {
            front[i] = min(x - front[i - 1], arr[i]); //尽量往前取
            back[i] = arr[i] - front[i];
        }  
    }
    return front[n] == 0; 
}

int main() {
    while (scanf("%d", &n) == 1 && n) {
        for (int i = 1; i <= n; i++) 
            scanf("%d", &arr[i]);

        if (n == 1) {
            printf("%d\n", arr[1]);
            continue;  
        } 

        arr[n + 1] = arr[1]; 
        int L = 0, R = 0;
        for (int i = 1; i <= n; i++) 
            L = max(L, arr[i] + arr[i + 1]);

        memset(front, 0,sizeof(front));
        memset(back, 0,sizeof(back));
        if (n % 2 == 1) {
            for (int i = 1; i <= n; i++) 
                R = max(R, arr[i] * 3);
            while (L < R) {
                int mid = L + (R - L) / 2;
                if (judge(mid)) 
                    R = mid;
                else
                    L = mid + 1; 
            } 
        }
        printf("%d\n", L); 
    }
    return 0;
}


你可能感兴趣的:(UVA1335-- Beijing Guards)