【算法刷题】动态规划 Day5
最近在复习期末,做题少了
今天做了一道题,这道题确实是好题
加上上次做了没写的一道题,就勉强成篇了
P1854 花店橱窗布置
题目描述
某花店现有 \(F\) 束花,每一束花的品种都不一样。至少有同样数量的花瓶,被按顺序摆成一行。花瓶的位置是固定的,从左到右按 \(1\sim V\) 顺序编号,\(V\) 是花瓶的数目。
花束可以移动,并且每束花用 \(1\sim F\) 的整数标识。所有花束在放入花瓶时必须保持其标识数的顺序。例如,假设杜鹃花的标识数为 \(1\),秋海棠的标识数为 \(2\),康乃馨的标识数为 \(3\),即杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中。每个花瓶只能放一束花。
每个花瓶的形状和颜色也不相同,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果,并以美学值(一个整数 \(a_{i,j}\))来表示,空置花瓶的美学值为 \(0\)。在上述的例子中,花瓶与花束的不同搭配所具有的美学值,可以用如下的表格来表示:
| 花瓶 1 | 花瓶 2 | 花瓶 3 | 花瓶 4 | 花瓶 5 | |
|---|---|---|---|---|---|
| 杜鹃花 | \(7\) | \(23\) | \(-5\) | \(-24\) | \(16\) |
| 秋海棠 | \(5\) | \(21\) | \(-4\) | \(10\) | \(23\) |
| 康乃馨 | \(-21\) | \(5\) | \(-4\) | \(-20\) | \(20\) |
根据表格,杜鹃花放在花瓶 \(2\) 中,会显得非常好看,但若放在花瓶 \(4\) 中,则显得很难看。
为了取得最佳的美学效果,必须在保持花束顺序的前提下,使花的摆放取得最大的美学值,如果具有最大美学值的摆放方式不止一种,则输出任何一种方案即可。
输入格式
输入文件的第一行是两个整数 \(F\) 和 \(V\),分别为花束数和花瓶数。
接下来是矩阵 \(a_{i,j}\),共 \(F\) 行,每行 \(V\) 个整数,\(a_{i,j}\) 表示花束 \(i\) 摆放在花瓶 \(j\) 中的美学值。
输出格式
输出文件的第一行是一个整数,为最大的美学值;接下来一行 \(F\) 个整数,为那束花放入那个花瓶的编号。
输入输出样例 #1
输入 #1
3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20
输出 #1
53
2 4 5
说明/提示
对于 \(100\%\) 的数据,\(1\le F\le V\le 100\)。
感谢 @罗恺 提供 SPJ
解法&&个人感想
我相信转移方程非常容易推出来,那么卡我们的就是这个搜索
因为上次记前驱的方法难以使用,便只能dfs
我们利用的原理就是,对于某盆花,其他的花一定摆在它前面
然后找到第一个与转移方程相符的(采用了贪心思想),然后接着搜
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x&(-x))
#define maxn 105
#define maxm 105
using namespace std;
int n,m;//n是花的数目,m是瓶子的数目
int ma[maxn][maxm];
int dp[maxm][maxn];//表示前i个花瓶放了j个花得到的最大值
const int INF=1e9;
stack<int>s;
void print(int x,int sum,int m){
if(x==0){
while(!s.empty()){
int tem=s.top();s.pop();
cout<<tem<<' ';
}
return ;
}
int temp=0;
for(int i=m;i>=x;i--){
if(sum-ma[x][i]==dp[i-1][x-1]){
temp=i;
s.push(i);
break;
}
}
print(x-1,sum-ma[x][temp],temp-1);
return ;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>ma[i][j];
}
}
for(int i=0;i<=m;i++){
for(int j=0;j<=n;j++) dp[i][j]=-INF;
}
for(int i=0;i<=m;i++) dp[i][0]=0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n&&j<=i;j++){
dp[i][j]=max(dp[i-1][j-1]+ma[j][i],dp[i-1][j]);
}
}
cout<<dp[m][n]<<endl;
print(n,dp[m][n],m);
system("pause");
return 0;
}
重点还是下面这道题
P2340 [USACO03FALL] Cow Exhibition G
题目背景
题目描述
奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对 \(N\) 头奶牛进行了面试,确定了每头奶牛的智商和情商。
贝西有权选择让哪些奶牛参加展览。由于负的智商或情商会造成负面效果,所以贝西不希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛的智商与情商之和越大越好,请帮助贝西求出这个最大值。
输入格式
第一行:单个整数 \(N\),\(1 \le N \le 400\)。
第二行到第 \(N+1\) 行:第 \(i+1\) 行有两个整数:\(S_i\) 和 \(F_i\),表示第 \(i\) 头奶牛的智商和情商,− \(1000 \le S_i;F_i \le 1000\)。
输出格式
输出单个整数:表示情商与智商和的最大值。贝西可以不让任何奶牛参加展览,如果这样做是最好的,输出 \(0\)。
输入输出样例 #1
输入 #1
5
-5 7
8 -6
6 -3
2 1
-8 -5
输出 #1
8
说明/提示
选择第一头,第三头,第四头奶牛,智商和为−5+6+2 = 3,情商和为7−3+1 = 5。再加
入第二号奶牛可使总和提升到10,不过由于情商和变成负的了,所以是不允许的
解法&&个人感想
至少这种题对于我这样的人是有初见杀的,为什么?
因为不知道这个看似零一背包的东西从何做起
那么,我们的数学建模就要大显身手了
既然看着像零一背包,那么我们肯定需要一个价值和一个体积
而题目中的两个量是对称且互不相关的,所以我们随便取其中一个为体积,另一个为容量
有人会问,诶你这个根本不符合体积的定义啊?我们体积是有上限的
对啊,体积是有上限的,题目的数据范围不是给你了吗(笑),我们遍历的时候按这个来就可以了,最终答案是下标与价值之和
也有人会问,诶你的数组下标有负数,这怎么办?
当然,我们可以采取一种“偏移的方式”,将负数转为正数,而正数变得更大,这样就可以避免负数下标了
然后我们就开始写代码,发现答案是错的,why?
我们从零一背包的角度来看,我们采用滚动数组时为什么要用逆序?
当然是避免小的数在更新大的数之前就被更新了
那么,这道题如果对于负数,我们逆序更新,不就是小的数在更新大的数(想想\(j-s[i]>j\))之前就被更新了吗?
好好想一想
所以我们要用这个数,而遍历的范围是整个数组(除了不让\(j-s[i]\)越界报错外,其他的都应该被更新)
另外,最后的\(d[i]>=0\),才能实现题目中所谓的如果怎么拿都不是最优,就不拿了的要求
初始化的值也要注意
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x&(-x))
#define maxt 801005//这个是数组的大小
#define maxm 400001//因为有负数,需要偏移量
#define maxn 405//这个是n的大小
using namespace std;
int n;
int s[maxn],f[maxn];
int dp[maxt];
const int INF=1e9;
int ans=-INF;
int main(){
for(int i=0;i<=maxt;i++) dp[i]=-INF;
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i]>>f[i];
}
dp[maxm]=0;
for(int i=1;i<=n;i++){
if(s[i]>=0){
for(int j=maxt;j>=s[i];j--){
dp[j]=max(dp[j-s[i]]+f[i],dp[j]);
}
}
else{
for(int j=0;j<=maxt+s[i];j++){
dp[j]=max(dp[j-s[i]]+f[i],dp[j]);
}
}
}
for(int i=maxm;i<=maxt;i++){
if(dp[i]>=0) ans=max(ans,i+dp[i]-maxm);
}
cout<<ans<<endl;
system("pause");
return 0;
}
期末加油,7.5还要一起看青猪第二季呢!
看了樱花庄,其实相比真白更欣赏的是七海,因为太贴近现实生活了
刻画的心理确实像极了你被各种竞赛爷/开发童子功同学吊打的样子
但是这作品只能称为神作而不是神中神的原因就在于,最后没让七海赢
毕竟,你看ED歌词写得很清楚,“I'm a dreamer"
我们下一期见!
(应该没人注意到我悄咪咪换了片尾)

浙公网安备 33010602011771号