2020.01.20刷题总结

问题 F: 维斯顿的烦劳

描述
维斯顿经营着一个盗版贩卖的商店(偶尔也会适应国家政策,摆地摊来扩大销售)。当然大家都愿意支持正版,可惜盗版生意依旧火爆,每次上货基本就是被一抢而空。为此维斯顿不断的扩大自己的商店,力求可以放下更多的商品,可惜现在手上的资金有限没法扩容商店,为了最快速的获得资金,那他就需要选择那些利润大的商品进行贩卖。我们假设商店可以放下V体积的物品。维斯顿在上货的时候有K件物品可以选择,每件物品有体积(S),和利润(P)两个特征。要在K件物品中选择一些物品体积总和不超过V。使得利润之和最大。

格式
输入格式
输入一个浮点数 V(V<=1000,modf(V)>=0.01),和一个整数 K(k<=100)
接着是K行,包含两个浮点数S,P,(S<=V,P<=100,modf(S)>=0.01)

输出格式
输出一个浮点数表示可以得到最大利润之和。

样例
样例输入 Copy

10 3
5 4
3 3
5 4

样例输出 Copy
8.000000

典型的背包问题,可是还是错了好多。因为V是浮点数,所以不能用来当作下标,这样一来就不能用记忆化数组,当时我就想用set来索引,可是错误百出,因为对set不熟悉,下面是错误的代码:

#include <bits/stdc++.h>
using namespace std;
struct node
{
    float v = 0, p = 0;
};
node a[110];
float v;
int k;
float max(float a, float b)
{
    return a > b ? a : b;
}
struct ans
{
    int i;
    float v;
    float ansr;
    bool operator<(const ans &a) const
    {
        if (this->i == a.i && this->v == a.v)
            return false;
        else
            return true;
    }
};
set<ans> mem;
float solove(int i, float v)
{
    ans t = {i, v};
    if (mem.count(t))
        return mem.find(t)->ansr;
    if (i == k)
        return 0;

    t.i = i, t.v = v;
    if (v < a[i].v)
        t.ansr = solove(i + 1, v);
    else
        t.ansr = max(solove(i + 1, v), solove(i + 1, v - a[i].v) + a[i].p);
    mem.insert(t);
    return t.ansr;
}
int main(void)
{
    cin >> v >> k;
    for (int i = 0; i < k; i++)
        cin >> a[i].v >> a[i].p;
    printf("%lf", solove(0, v));
    //cout<<solove(0,v);
    return 0;
}

后来仔细看题,发现一个东西:modf(V)>=0.01
!!!我可以把V*100,这样不就可以转换成整数了嘛,最后ans/100不就行了,早看到这个也不会让我瞎琢磨那么久了(仔细审题很重要)。
下面是AC代码:

#include <bits/stdc++.h>
using namespace std;
double max(double a, double b)
{
    return a > b ? a : b;
}
struct obj
{
    int s;
    double p;
};
int main(void)
{
    double t;
    int v, k;
    obj a[110];
    double dp[110000] = {0};
    cin >> t >> k;
    v = t * 100;
    for (int i = 1; i <= k; i++)
    {
        cin >> t >> a[i].p;
        a[i].s = t * 100;
    }

    for (int i = 1; i <= k; i++)
        for (int j = v; j > 0; j--)
            if (j >= a[i].s)
                dp[j] = max(dp[j], dp[j - a[i].s] + a[i].p);

    printf("%lf\n", dp[v]);
    return 0;
}

问题 A: 切绳子

描述
有n条绳子,长度分别为L[i]。如果从他们中切割出k条长度相同的绳子的话,这k条绳子每条最长能有多长?(答案保留小数点后两位(直接舍掉两位后的小数),规定1单位长度的绳子最多可以切割成100份)

格式
输入格式
包含多组输入
输入n,k,(1<=n,k<=10000)
然后n行,输入L[i],代表每一条绳子的长度(1<=L[i]<=100000)

输出格式
切出k条长度相等的绳子最大长度是多少,输出保留两位小数

样例

样例输入 Copy

4 11

8.02

7.43

4.57

5.39

样例输出 Copy

2.00

这题其实简单,但是犯了一个非常粗心的错误,没有把double转换成int,所以结果有问题:

bool check(double ans)
{
    int count = 0;
    for (int i = 0; i < n; i++)
        count += (int)L[i] / ans;
    if (count >= k)
        return true;
    return false;
}

改完之后:

bool check(double ans)
{
    int count = 0;
    for (int i = 0; i < n; i++)
        count += (int)L[i] /(int)ans;
    if (count >= k)
        return true;
    return false;
}

AC代码:

#include <bits/stdc++.h>
#define INF ((unsigned(-1)) >> 1)
using namespace std;
const int maxn = 10010;
int n, k;
double L[maxn];
bool check(double ans)
{
    int count = 0;
    for (int i = 0; i < n; i++)
        count += (int)L[i] / (int)ans;
    if (count >= k)
        return true;
    return false;
}
int main(void)
{
    while (cin >> n >> k)
    {
        double l = 0, r = INF, mid = (l + r) / 2, ans = 0;
        for (int i = 0; i < n; i++)
        {
            cin >> L[i];
            L[i] *= 100;
        }
        while (l <= r)
        {
            if (check(mid))
            {
                ans = mid;
                l = mid + 1;
            }
            else
                r = mid - 1;
            mid = (l + r) / 2;
        }
        printf("%.2lf\n", ans / 100);
    }
    return 0;
}

问题 B: 如何放牛

描述
农夫有n个牛栏,m头牛,然后要让你把m个牛都放进牛栏里,让两头牛之前的最大的最小距离

格式
输入格式
多组输入
输入n,m (1<=m<=n<=100000)
下面n行是牛栏的位置xi (0 <= xi <=1,000,000,000)

输出格式
输出两头牛最大的最小距离

样例
样例输入 Copy
5 3
1
2
8
4
9
样例输出 Copy
3

提示
FJ可以将他的3头奶牛放在位置1,4和8的摊位上,最小距离为3.

大量输入数据,建议使用scanf。

就如题目提示一样,我用cin超时了。还有就是,check函数想当然的去写,结果错了,后来排查半天才出来。哎,菜是原罪。
这是错误的check:

bool check(int mid)
{
    int count = 0;
    int begin = 0, end = 1;
    while (end < n)
    {
        while (end < n && x[end] - x[begin] < mid)
            end++;
        if (x[end] - x[begin] >= mid)
            count++;
        else
            return false;
        begin = end, end = end + 1;
    }
    if (count >= m)
        return true;
    return false;
}

我以为 if (x[end] - x[begin] >= mid) 满足的话,说明end已经大于等于n了,可是没考虑到end等于n的时候,越界后x[end]的结果未知,所以if的成立也未知,然后就WA了。
改之后的代码:

bool check(int mid)
{
    int count = 1;
    int begin = 0, end = 1;
    while (end < n)
    {
        while (end < n && x[end] - x[begin] < mid)
            end++;
        if (end < n && x[end] - x[begin] >= mid)
            count++;
        begin = end, end = end + 1;
    }
    if (count >= m)
        return true;
    return false;
}

AC代码:

#include <bits/stdc++.h>
typedef unsigned long long ull;
#define INF ((unsigned(-1)) >> 1)
const int maxn = 100100;
ull x[maxn];
int n, m;
using namespace std;
bool check(int mid)
{
    int count = 1;
    int begin = 0, end = 1;
    while (end < n)
    {
        while (end < n && x[end] - x[begin] < mid)
            end++;
        if (end < n && x[end] - x[begin] >= mid)
            count++;
        begin = end, end = end + 1;
    }
    if (count >= m)
        return true;
    return false;
}
int main(void)
{
    while (cin >> n >> m)
    {
        for (int i = 0; i < n; i++)
            scanf("%llu", x + i);
        sort(x, x + n);
        int l = 0, r = INF, mid = (l + r) / 2, ans = 0;
        while (l <= r)
        {
            if (check(mid))
            {
                ans = mid;
                l = mid + 1;
            }
            else
                r = mid - 1;
            mid = (l + r) / 2;
        }
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值