算法訓練:考前臨時抱佛腳(搜索/DP/揹包)

題目如下

csdn效果顯示不好,原題目鏈接:洛谷P2392

題目背景

kkksc03 的大學生活非常的頹廢,平時根本不學習。但是,臨近期末考試,他必須要開始抱佛腳,以求不掛科。

題目描述

這次期末考試,kkksc03 需要考 44 科。因此要開始刷習題集,每科都有一個習題集,分別有 s_1,s_2,s_3,s_4s1​,s2​,s3​,s4​ 道題目,完成每道題目需要一些時間,可能不等。

kkksc03 有一個能力,他的左右兩個大腦可以同時計算 22 道不同的題目,但是僅限於同一科。因此,kkksc03 必須一科一科的複習。

由於 kkksc03 還急着去處理洛谷的 bug,因此他希望儘快把事情做完,所以他希望知道能夠完成複習的最短時間。

輸入格式

本題包含 55 行數據:第 11 行,爲四個正整數 s_1,s_2,s_3,s_4s1​,s2​,s3​,s4​。

第 22 行,爲 A_1,A_2,\ldots,A_{s_1}A1​,A2​,…,As1​​ 共 s_1s1​ 個數,表示第一科習題集每道題目所消耗的時間。

第 33 行,爲 B_1,B_2,\ldots,B_{s_2}B1​,B2​,…,Bs2​​ 共 s_2s2​ 個數。

第 44 行,爲 C_1,C_2,\ldots,C_{s_3}C1​,C2​,…,Cs3​​ 共 s_3s3​ 個數。

第 55 行,爲 D_1,D_2,\ldots,D_{s_4}D1​,D2​,…,Ds4​​ 共 s_4s4​ 個數,意思均同上。

輸出格式

輸出一行,爲複習完畢最短時間。

輸入輸出樣例

輸入 #1複製

1 2 1 3		
5
4 3
6
2 4 3

輸出 #1複製

20

說明/提示

1≤s1​,s2​,s3​,s4​≤20。

1≤A,B,C,D≤60。

 

 



分析:

踩坑記錄:

由於搜索算法練的不多,現在只是蒟蒻,加上未能正確理解題目的意思,陷入瞭如何排列題目的死潭中。。。。。首先想到將題目的全排列寫出,每次做兩個不同的題目,顯然N已經達到了20.全排列必然超時。。。加入剪枝(減去大於已經記錄的最小值時直接退出),仍然超時。。。。。只能過一個樣例。。。

沒辦法,看題解!!!!

 

果然,我確實是個菜雞,大佬們第一眼看到就想到貪心,而我卻是全排列題目順序。。。還好貪心不是正確思路,哈哈哈

 

先說直接爆搜的方法

只要能理解這道題目的意思:加入某一道題被左腦選中,整道題必須由左腦來完成!!!同樣的道理,被右腦選中只能被右腦獨立完成。!!!因此,題目的意思就被轉化成,怎樣選才能使做完的時間最少(有點像均衡使用左右腦的意味)顯然每道題只有兩種狀態:被左腦選中和被右腦選中。枚舉即可,由於此題數據較小,不需要剪枝就能AC

#include <bits/stdc++.h>
using namespace std;

const int MAX = 100005;
const int INF = 0x7fffffff;

int a[MAX];int cate[4];
int res;

void dfs(int index,int l,int r,int s) {
    if(index==s) {
        res = min(res,max(l,r));    //首先,做完該習題所用的時間是左右腦中較大的,然後保存較小的排列時間
        return;
    }
    dfs(index+1,l+a[index],r,s);    //被左腦選中
    dfs(index+1,l,r+a[index],s);    //被右腦選中
}

int main() {
    for (int i = 0; i < 4; ++i) {
        scanf("%d",&cate[i]);
    }
    int count = 0;
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < cate[i]; ++j) {
            scanf("%d",&a[j]);
        }
        res = INF;    //INF代表無窮大,方便比較
        dfs(0,0,0,cate[i]);
        count+=res;
    }
    printf("%d\n",count);
}

 

動態規劃/01揹包

 

由上面的分析,可以知道每道題都有兩種狀態,考慮動態規劃中01揹包問題。

假設被左腦選中,爲裝入揹包的狀態。右腦則是不放入。。。

接下來考慮揹包的容量:由上面的分析得到,要使完成的時間最小,左腦右腦完成的工作要儘可能一樣。故可以假設揹包的容量爲總體所需時間的一般。

此時,求出dp數組,dp的結果就代表左腦最多完成一半工作的時間!!!故右腦的時間一定大於等於左腦!!!

OK,上01揹包的板子,代碼如下

#include <bits/stdc++.h>
using namespace std;

const int MAX = 100;
const int INF = 0x7fffffff;

int a[MAX];int cate[4];
int dp[MAX];

int main() {
    for (int i = 0; i < 4; ++i) {
        scanf("%d",&cate[i]);
    }
    int count = 0;
    for (int i = 0; i < 4; ++i) {
        int sum =0;
        for (int j = 0; j < cate[i]; ++j) {
            scanf("%d",&a[j]);
            sum+=a[j];
        }
        memset(dp,0, sizeof(dp));
        for (int k = 0; k < cate[i]; ++k) {
            for (int m = sum/2; m >= a[k];m--) {
                dp[m]=max(dp[m],dp[m-a[k]]+a[k]);
            }
        }
//        count+=max(dp[sum/2],sum-dp[sum/2]); //如果不能理解下一步的操作,可以用它代替下一行
        count+=sum-dp[sum/2];
    }
    printf("%d\n",count);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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