(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;
}










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