《挑战程序设计竞赛》3.1.1 二分搜索-最大化最小值 POJ1064 2456 3258 3273 3104 3045

POJ1064

http://poj.org/problem?id=1064

题意

给出n条线段,以米的单位给出,小数点后两位(精确到厘米),要你对这些线段裁剪,裁剪出m条等长的线段,并且让这些线段尽可能长另外线段的长度不能小于1厘米,如果筹不够m条,输出0.00。

思路

很明显的用二分法求解题目,二分法的的试验值实际上为题目增加了一个条件,加上这个条件判断是否符合题目要求即可。
但需要注意答案的精度会对判断结束条件有要求。这个题答案要求小数点后两位数精度,那么二分法判断范围最高为0.01,实际上最好更低一些,0.0001更好。当然《挑战》书中给出的二分法循环100次能够让精度更高,也是不错的方法。

代码

Source Code

Problem: 1064       User: liangrx06
Memory: 320K        Time: 125MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

const int N = 10000;
const int INF = 0x3f3f3f3f;

int n, k;
double a[N];

bool check(double mid)
{
    int cnt = 0;
    for (int i = 0; i < n; i ++)
        cnt += a[i]/mid;
    return cnt >= k;
}

int main(void)
{
    cin >> n >> k;
    for (int i = 0; i < n; i ++)
        scanf("%lf", &a[i]);

    double lb = 0, ub = INF;
    while (ub - lb > 0.001) {
        double mid = (lb + ub) / 2;
        if (check(mid)) lb = mid;
        else ub = mid;
    }
    printf("%.2lf\n", floor(ub*100) * 0.01);

    return 0;
}

POJ2456

http://poj.org/problem?id=2456

题意

描述
农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,…,xN (0 <= xi <= 1,000,000,000).
但是,John的C (2 <= C <= N)头牛们并不喜欢这种布局,而且几头牛放在一个隔间里,他们就要发生争斗。为了不让牛互相伤害。John决定自己给牛分配隔间,使任意两头牛之间的最小距离尽可能的大,那么,这个最大的最小距离是什么呢?
输入
有多组测试数据,以EOF结束。
第一行:空格分隔的两个整数N和C
第二行——第N+1行:分别指出了xi的位置
输出
每组测试数据输出一个整数,满足题意的最大的最小值,注意换行。
样例输入
5 3
1
2
8
4
9
样例输出
3

思路

这是一个最小值最大化的问题。先对隔间编号从小到大排序,则最大距离不会超过两端的两头牛之间的差值,最小值为0。所以我们可以通过二分枚举最小值来求。假设当前的最小值为x,如果判断出最小差值为x时可以放下C头牛,就先让x变大再判断;如果放不下,说明当前的x太大了,就先让x变小然后再进行判断。直到求出一个最大的x就是最终的答案。

代码

Source Code

Problem: 2456       User: liangrx06
Memory: 640K        Time: 125MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 100000;
const int INF = 0x3fffffff;

int n, k;
int a[N];

bool check(int mid)
{
    int x = a[0];
    int cnt = 1;
    for (int i = 1; i < n; i ++) {
        if (x+mid <= a[i]) {
            x = a[i];
            cnt ++;
        }
    }
    return cnt >= k;
}

int main(void)
{
    cin >> n >> k;
    for (int i = 0; i < n; i ++)
        scanf("%d", &a[i]);
    sort(a, a+n);

    int lb = 0, ub = INF;
    while (ub - lb > 1) {
        int mid = (lb + ub) / 2;
        if (check(mid)) lb = mid;
        else ub = mid;
    }
    printf("%d\n", lb);

    return 0;
}

POJ3258

http://poj.org/problem?id=3258

题意

牛要到河对岸,在与河岸垂直的一条线上,河中有N块石头,给定河岸宽度L,以及每一块石头离牛所在河岸的距离,现在去掉M块石头,要求去掉M块石头后,剩下的石头之间以及石头与河岸的最小距离的最大值。

思路

二分法求解,定义函数 check() 求距离x能否留下n-m个石子。循环结束条件是ub - lb > 1。
另外,此文对该题的思路做了更详尽的解析:
poj3258 二分及一些思考

代码

Source Code

Problem: 3258       User: liangrx06
Memory: 444K        Time: 157MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 50000;
const int INF = 0x3fffffff;

int l, n, m;
int a[N];

bool check(int mid)
{
    int x = 0;
    int cnt = 0;
    for (int i = 0; i < n; i ++) {
        if (x+mid <= a[i]) {
            x = a[i];
            cnt ++;
        }
    }
    if (x+mid <= l)
        cnt ++;
    return cnt >= n-m+1;
}

int main(void)
{
    cin >> l >> n >> m;
    for (int i = 0; i < n; i ++)
        scanf("%d", &a[i]);
    sort(a, a+n);

    int lb = 0, ub = INF;
    while (ub - lb > 1) {
        int mid = (lb + ub) / 2;
        if (check(mid)) lb = mid;
        else ub = mid;
    }
    printf("%d\n", lb);

    return 0;
}

POJ3273

http://poj.org/problem?id=3273

题意

给N个数,划分为M个块(不得打乱数顺序)。找到一个最好的划分方式,使得块中的最大值 最小。

思路

块的和最小大于最大数值,最大小于数值总和。因此,我们首先判断块的上限值(即我们要求的值),以该上限判断结果的划分是否符合要求。若划分的块数大于M,则我们二分式地减小这个上限;反之我们二分式地增加这个上限。

代码

Source Code

Problem: 3273       User: liangrx06
Memory: 632K        Time: 125MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 100000;
const int INF = 0x3fffffff;

int n, m;
int a[N];

bool check(int mid)
{
    int sum = 0;
    int cnt = 1;
    for (int i = 0; i < n; i ++) {
        if (a[i] > mid)
            return false;
        if (sum + a[i] > mid) {
            sum = a[i];
            cnt ++;
        }
        else
            sum += a[i];
    }
    return cnt <= m;
}

int main(void)
{
    cin >> n >> m;
    for (int i = 0; i < n; i ++)
        scanf("%d", &a[i]);

    int lb = 0, ub = INF;
    while (ub - lb > 1) {
        int mid = (lb + ub) / 2;
        if (check(mid)) ub = mid;
        else lb = mid;
    }
    printf("%d\n", ub);

    return 0;
}

POJ3104

http://poj.org/problem?id=3104

题意

有一些衣服,每件衣服有一定水量,有一个烘干机,每次可以烘一件衣服,每分钟可以烘掉k滴水。每件衣服没分钟可以自动蒸发掉一滴水,用烘干机烘衣服时不蒸发。问最少需要多少时间能烘干所有的衣服。

思路

首先可以想到二分枚举答案。枚举一个mid值时,若一件衣服的水量大于mid,则一件衣服的最短时间是烘干一段时间,在自己蒸发一段时间。可以算出烘干的时间,为(a[i] - mid) / (k - 1)。这样把所有衣服的时间加起来,判断可行即可。
但此题可能还需要注意k=1的情况。(虽然测试数据似乎没有出现k=1的情况)

代码

Source Code

Problem: 3104       User: liangrx06
Memory: 640K        Time: 766MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

const int N = 100000;
const int INF = 0x3fffffff;

int n, k;
int a[N];

bool check(int mid)
{
    int time = mid;
    for (int i = 0; i < n; i ++) {
        if (a[i] > mid)
            time -= ceil((double)(a[i]-mid)/(k-1));
        if (time < 0)
            return false;
    }
    return time >= 0;
}

int main(void)
{
    cin >> n;
    for (int i = 0; i < n; i ++)
        scanf("%d", &a[i]);
    cin >> k;

    int ans;
    if (k == 1) {
        ans = 0;
        for (int i = 0; i < n; i ++)
            ans = max(ans, a[i]);
    }
    else
    {
        int lb = 0, ub = INF;
        while (ub - lb > 1) {
            int mid = (lb + ub) / 2;
            if (check(mid)) ub = mid;
            else lb = mid;
        }
        ans = ub;
    }
    printf("%d\n", ans);

    return 0;
}

POJ3045

http://poj.org/problem?id=3045

题意

有N头牛要叠罗汉,每头牛都有相应的重量和力量。
叠罗汉是有危险的,每头牛的危险系数为该牛上面的牛的重量的和减去该牛的力量。
问如何安排这个叠罗汉顺序,使得危险系数最大的那头牛的危险系数最小。

思路

最大值的最小值,用二分?二分当然也可以,但是有更简便的方法。
不妨设所有牛都按最优顺序排好了,考虑相邻的两头牛i和i+1,如果交换他们的位置,那么对前面和后面的结果都无影响,只是他们两个的风险值变化了(变大了),于是我们可以得到这个时候i和i+1的关系
设w1+w2+…+wi-1=W
那么如果i和i+1不交换:
i的风险值:W-si ①
i+1的风险值:W+wi-si+1 ②
如果i和i+1交换:
i+1(现在在第i个位置)的风险值:W-si+1 ③
i(现在在第i+1个位置)的风险值:W+wi+1-si ④
很容易可以看出②>③,④>①,而又假设原顺序是最优的,那么后来交换后肯定不是最优的,即②<④,即wi+si < wi+1+si+1,即最优序列一定满足wi+si < wi+1+si+1
所以算法很简单,按wi+si排序即可,这个题用贪心法
总结:看见求最大的最小不能定式思维二分,当二分不行时可以观察题目的特点,抓住特点很重要。

代码

Source Code

Problem: 3045       User: liangrx06
Memory: 640K        Time: 110MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 50000;
const int INF = 0x3fffffff;

struct Cow{
    int w, s;
};

bool cmp(const Cow& a, const Cow& b)
{
    return a.w+a.s < b.w+b.s;
}

int main(void)
{
    int n;
    Cow c[N];

    cin >> n;
    for (int i = 0; i < n; i ++)
        scanf("%d%d", &c[i].w, &c[i].s);
    sort(c, c+n, cmp);

    int ans = -INF, sum = 0;
    for (int i = 0; i < n; i ++) {
        ans = max(ans, sum - c[i].s);
        sum += c[i].w;
    }
    printf("%d\n", ans);

    return 0;
}        
根据引用,你遇到的问题是在运行vite项目时出现了命令错误。根据错误提示信息,"vite"不是内部或外部命令,也不是可运行的程序。这可能是因为你的系统环境中没有安装vite或者没有正确配置vite的路径。 要解决这个问题,你可以按照以下步骤进行操作: 1. 确保你已经在项目中正确安装了vite。你可以使用以下命令来全局安装vite: ``` npm install -g create-vite ``` 2. 确认你的系统环境变量中是否配置了vite的路径。你可以通过在终端中输入以下命令来检查vite是否能够正确运行: ``` vite -v ``` 如果你没有看到vite的版本信息,那么你需要将vite的路径添加到环境变量中。具体的操作取决于你使用的操作系统。 3. 如果你已经正确安装了vite并配置了环境变量,但仍然遇到了问题,那么可能是你的项目中的配置有误。你可以尝试重新安装项目依赖并重新启动项目: ``` npm install npm run dev ``` 如果你按照上述步骤操作后仍然遇到问题,请提供更多的错误信息以便我们更好地帮助你解决问题。<span class="em">1</span> #### 引用[.reference_title] - *1* [使用Vite启动vue项目 通过IP访问](https://blog.csdn.net/wocaishiryr/article/details/124962809)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值