題目如下
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);
}