我的想法是始终选一个耗时少的脑,将目前最大值放入。
但是题解这个方法不行,有没dl解释下为什么?
但是
#include <iostream>
#include <vector>
#include <algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 10000;
ll n;
ll a[N][N], s[N], b[N], x[N], y[N];
bool vod(int a, int b) {
return a > b;
}
void solve() {
ll ans = 0;
for (int i = 1;i <= 4;i++) {
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for (int j = 1;j <= s[i];j++) {
b[j] = a[i][j];
}
sort(b + 1, b + s[i] + 1, vod);
x[1] = b[1];y[1] = 0;
for (int j = 2;j <= s[i];j++) {
if (x[j-1] == y[j-1]){
x[j] = x[j - 1] + b[j];y[j] = y[j - 1];
}
else {
x[j] = min(x[j - 1], y[j - 1]) == x[j - 1] ? x[j - 1] + b[j] : x[j - 1];
y[j] = min(x[j - 1], y[j - 1]) == y[j - 1] ? y[j - 1] + b[j] : y[j - 1];
}
}
ans += max(x[s[i]], y[s[i]]);
}
cout << ans << endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
for (int i = 1;i <= 4;i++) {
cin >> s[i];
}
for (int i = 1;i <= 4;i++) {
for (int j = 1;j <= s[i];j++) {
cin >> a[i][j];
}
}
solve();
return 0;
}
很显然,用时越短,意味着脑闲置的时间越少
而两个题必须是同一科,那么就要把每一科分成AB两组,两组的用时越接近越好
用贪心算法的话,可以快速得到一个次优解,但是几乎可以肯定不是最优解
我随便举个例子:
5,4,3,3,3
很显然5,4一组,3,3,3一组,两边相等,用时9
而用贪心算法,先排序,然后按顺序塞进短的列表里面,就会把5和4分开
变成5,3一组,4,3,3一组,这样用时是10
贪心会爆
题解(luogu)
#include<bits/stdc++.h>
using namespace std;
int a[5],i,j,k,sum,t,homework[21],dp[2501];
int main(){
for(i=1;i<=4;i++)
cin>>a[i];
for(i=1;i<=4;i++){
sum=0;
for(j=1;j<=a[i];j++)
{cin>>homework[j];//输入
sum+=homework[j];}//总时间累加
for(j=1;j<=a[i];j++)
for(k=sum/2;k>=homework[j];k--)//只要是总和的一半
dp[k]=max(dp[k],dp[k-homework[j]]+homework[j]);//01背包
t+=sum-dp[sum/2];//累加为另一个脑子
for(j=1;j<=sum/2;j++)
dp[j]=0;//清零
}
cout<<t;//输出
return 0;
}
相同点 :
动态规划和分治算法类似,其基本思想也是将待求的解问题分解成若干个子问题,先求解子问题,然后从这些子问题得到原问题的解
不同点 :
与分治算法不通的是,适用于动态规划的去求解决的问题,在分解之后的子问题往往不是相互独立的。在分治算法中有些子问题已经被计算了很多次,浪费了大量的时间,而动态规划就很好的解决了这个问题,例如已经保存了子问题的答案,当再需要使用时,就可以直接调用,避免了大量的重复计算
为了达到这个目的,可以用一个表来记录所有已经解决的子问题的答案,无论子问题是否被用到,只要计算过就填入表中,这就是动态规划的基本思想。
动态规划算法适用于解最优化问题,通常可以按如下几个步骤
(1) 找出最优解的性质,并刻画其结构特征
(2) 递归地定义最优值
(3) 以自底向上的方式计算出最优值
(4) 根据计算最优值是的信息,构造最优解
动态规划算法的基本要素
- 最优子结构性质
- 子问题重叠性质
典型例子:最长公共子序列,最大字段和,0-1背包问题。
这里有一个0-1背包个人觉得挺好理解的博客
根据参考资料中的代码和问题描述,我们可以得到以下结论:
问题描述中提到的“考前临时抱佛脚”方法是指每次选择一个耗时较少的脑题,并将当前解答的最大值放入。然而,题解中指出这种方法是行不通的。下面我们来解释一下原因。
根据参考资料中的归纳法,我们可以将路径交叉的情况归结为三种情况:
第1种情况:对于每一次移动i,第i次移动距离都比第i-2次移动距离更长。也就是说,路径每次都向外扩散。
第2种情况:对于每一次移动i,第i次移动的距离都比第i-2次移动距离更短。也就是说,路径每次都向内收缩。
第3种情况:对于每一次移动ij,都满足第2种情况。
针对这三种情况,题解中的代码分情况处理。其中,第1种和第2种情况的处理是比较直接的,而第3种情况的处理稍微复杂一些。
对于第3种情况,有以下两种情形:
第3.1种情况:第j次移动距离小于第j-2次移动距离减去第j-4次移动距离的差。此时,第j+1次移动距离需要小于第j-1次移动距离才能不出现路径交叉。
第3.2种情况:第j次移动距离大于等于第j-2次移动距离减去第j-4次移动距离的差,且小于等于第j-2次移动距离。此时,第j+1次移动距离需要小于第j-1次移动距离减去第j-3次移动距离的差,才能不出现路径交叉。
综上所述,题解中的代码根据以上的判断条件进行了处理,并最终得出是否路径交叉的结论。
所以,使用降序加贪心的方法不能解决问题,因为该方法没有考虑到路径交叉的情况,并且没有按照题解中的判断条件进行处理。