1. 程式人生 > 其它 >2020.01.20刷題總結

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