(06-07)二分

1、UVALive 3971 Assemble 組裝電腦


分析:最小值最大問題,一般採用二分來解決。。。本題核心:品質因子儘量大

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iostream>

using namespace std;

int cnt;
map<string, int> id;
int ID(char* s){
    if (!id.count(s)) id[s] = cnt++;
    return id[s];
}  //添加編號
 
struct Component
{
    int price;
    int quality;
};
const int maxn = 1005;
int n, b;
vector<Component> comp[maxn];
//檢測當前品質是否符合
bool ok(int q){
    int sum = 0;
    for (int i = 0; i<cnt; i++)
    {
        int cheapest = b+1, m = comp[i].size();
        for (int j = 0; j<m; j++)
            if (comp[i][j].quality >= q) cheapest = min(cheapest, comp[i][j].price);  //找每種類型的最便宜且滿足品質的物品
        if (cheapest == b+1) return false;
        sum += cheapest;
        if (sum > b ) return false;   
    }
    return true;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &b);
        cnt = 0;
        for (int i = 0; i<n; i++){
            comp[i].clear();
        }
        id.clear();
        int maxa = 0;
        for (int i = 0; i<n; i++)
        {
            char type[25], name[25];
            int quality, price;
            scanf("%s%s%d%d", type, name, &price, &quality);
            comp[ID(type)].push_back((Component){price, quality});   
            maxa = max(maxa, quality);
        }
        int L = 0, R = maxa;
        while (L<R)  //二分查找
        {
            int M = L + (R-L+1)/2;
            if (ok(M)) L = M;
            else R = M-1;
        }
        printf("%d\n", L);
    }
    return 0;
}

2、UVALive 3635 Pie 派

分析:二分查找,把問題轉化爲 “ 是否可以讓每個人得到一塊麪積爲 x 的派 ”;之後判斷x是否存在矛盾即可

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

using namespace std;

const double PI = acos(-1.0);  // PI 
const int maxn = 10005;

double A[maxn];
int n, f;

bool ok(double area)
{
    int sum = 0;
    for (int i = 0; i<n; i++)
        sum += floor(A[i] / area);  // 每個圓形派可以切成 [PI*r*r]/x 個派
    return sum >= f+1;              // 判斷是否存在矛盾
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d %d", &n, &f);
        double maxa = 0;
        for (int i = 0; i<n; i++)
        {
            int r;
            scanf("%d", &r);
            A[i] = PI*r*r;
            if (maxa < A[i]) {
                maxa = A[i];
            }
        }
        double L = 0, R = maxa; 
        while (R-L > 1e-5)  //double 類型判斷是否相等
        {
            double M = (L+R)/2;
            if (ok(M)) L = M;
            else R = M;
        }
        printf("%.4lf\n", L);
    }
    return 0;
}

3、UVALive 3177 Beijing Guard 長城守衛


分析:當n爲偶數, 答案肯定是相鄰兩個人的r值之和的最大值,即 p = max{r[i] + r[i+1]};

當n爲奇數, 這時候需要二分答案 ,假設第一個人的禮物爲 1 ~ r1,那麼最優的分配策略應該如此:編號爲偶數的儘量靠前取,編號爲奇數的儘量往後取,最後判定編號爲1 和編號爲n所取禮物是否衝突即可。

所以只需記載每個人在 1~r[1]取了幾個,在r[1]+1~r[n]取了幾個便可(本題分別用le[], ri[]表示)


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

using namespace std;

const int maxn = 100005;
int n, r[maxn], le[maxn], ri[maxn];

bool ok(int p)
{
    int x = r[1], y = p - r[1];
    le[1] = x;
    ri[1] = 0;
    for (int i = 2; i<=n; i++)
    {
        if (i%2 == 1)    //儘量往後取
        {
            ri[i] = min(y - ri[i-1], r[i]);
            le[i] = r[i] - ri[i];
        }
        else             //儘量往前取
        {
            le[i] = min(x - le[i-1], r[i]);
            ri[i] = r[i] - le[i];
        }
    }
    return le[n] == 0;  //判斷1和n是否產生衝突
}


int main()
{
    while (scanf("%d", &n) && n)
    {
        for (int i = 1; i<=n; i++) scanf("%d", &r[i]);
        if (n == 1) {     //特判 n == 1
            printf("%d\n", r[1]);
            continue;
        }
        r[n+1] = r[1];
        int L = 0, R = 0;
        for (int i = 1; i<=n; i++) L = max(L, r[i]+r[i+1]);//偶數時的至少禮物數
        if (n%2 == 1)
        {
            for (int i = 1; i<=n; i++) R = max(R, r[i]*3);//構造最大情況
            while (L<R)
            {
                int M = (R-L)/2 + L;
                if (ok(M)) R = M;
                else L = M+1;
            }
        }
        printf("%d\n", L);
    }
    return 0;
}










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章