首页 > 其他分享 >洛谷题单指南-动态规划2-P1854 花店橱窗布置

洛谷题单指南-动态规划2-P1854 花店橱窗布置

时间:2024-05-06 15:23:23浏览次数:26  
标签:花店 花瓶 int 洛谷题 朵花 美学 ans P1854 dp

原题链接:https://www.luogu.com.cn/problem/P1854

题意解读:F束花依次放入V个花瓶,每个花瓶最多一朵,且花的顺序在花瓶中递增,计算最大的美学值,并且输出每朵花具体放置方案。

解题思路:

首先想到的的DFS法,对于每一朵花,枚举所有的摆放方案,累加美学值,并记录放置位置,完成一种方案就记录最大美学值和对应的摆放位置。

尽管知道会超时,先拿到部分分再说!

19分代码-DFS:

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

const int N = 105;
int f, v;
int a[N][N];
int b[N]; //一个方案
int maxx = -2e9, ans[N]; //最大美学值,ans是最大美学值情况下每一朵花的方案

//考察第x朵花,前x-1朵花的美学值之和为sum
void dfs(int x, int sum)
{
    if(x > f)
    {
        if(sum > maxx)
        {
            maxx = sum;
            for(int i = 1; i <= f; i++) ans[i] = b[i]; //将b的方案拷贝到ans
        }
        return;
    }
    for(int i = b[x-1] + 1; i <= v; i++) //枚举第x朵花可以放置的花瓶,从第x-1朵花放置的花瓶数+1开始
    {
        b[x] = i; //把第x朵花放入i花瓶
        dfs(x + 1, sum + a[x][i]);
        b[x] = 0; //回溯
    }
}

int main()
{
    cin >> f >> v;
    for(int i = 1; i <= f; i++)
        for(int j = 1; j <= v; j++)
            cin >> a[i][j];

    dfs(1, 0);
    cout << maxx << endl;
    for(int i = 1; i <= f; i++) cout << ans[i] << " ";
    
    return 0;
}

如何对DFS代码进行优化,想到了记忆化搜索+剪枝,这里有一个特点:

对于每一朵花,枚举放置的位置一定是越来越靠后,而每朵花前面放置时的美学值如果比后面放置时的美学值大,那么后面的dfs可以提前结束,

因为再考察下去也无法得到最大美学值。

因此,可以记录mem[第x朵花][第x-1朵花的花瓶] = 考察第x朵花且已知第x-1朵花放置的花瓶时的美学值之和

100分代码-DFS+记忆化+剪枝:

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

const int N = 105;
int f, v;
int a[N][N];
int b[N]; //一个方案
int mem[N][N]; //mem[i][j]记录第i朵花,第i-1朵花放置的花瓶是j时的美学值之和
int maxx = -0x3f3f3f3f, ans[N]; //最大美学值,ans是最大美学值情况下每一朵花的方案

//考察第x朵花,前x-1朵花的美学值之和为sum
void dfs(int x, int sum)
{
    if(sum <= mem[x][b[x-1]]) return; //如果当前sum比之前记录的要小或相等,不用继续dfs,提前结束
    mem[x][b[x-1]] = sum; //记录第x朵花 第x-1花放置的花瓶位置 对应的美学值之和
    if(x > f)
    {
        if(sum > maxx)
        {
            maxx = sum;
            for(int i = 1; i <= f; i++) ans[i] = b[i]; //将b的方案拷贝到ans
        }
        return;
    }
    for(int i = b[x-1] + 1; i <= v; i++) //枚举第x朵花可以放置的花瓶,从第x-1朵花放置的花瓶数+1开始
    {
        b[x] = i; //把第x朵花放入i花瓶
        dfs(x + 1, sum + a[x][i]);
        b[x] = 0; //回溯
    }
}

int main()
{
    cin >> f >> v;
    for(int i = 1; i <= f; i++)
        for(int j = 1; j <= v; j++)
            cin >> a[i][j];

    memset(mem, -0x3f, sizeof(mem));
    dfs(1, 0);
    cout << maxx << endl;
    for(int i = 1; i <= f; i++) cout << ans[i] << " ";
    
    return 0;
}

本题正解应该是动态规划,

设dp[i][j]表示前i朵花放入前j个花瓶的最大美学值, a[i][j]是第i朵花放入j号花瓶的美学值

当i放入j:dp[i][j] = dp[i-1][j-1] + a[i][j]

当i不放入j:dp[i][j] = dp[i-1][j]

因此:dp[i][j] = max(dp[]i-1[j], dp[i-1][j-1] + a[i][j])

初始化:

由于有负数,dp初始化为负无穷,memset(dp, -0x3f, sizeof(dp));且dp[0][j]  = 0,前0朵花的美学值是0。

结果:dp[f][v]

记录具体方案:

用 struct node {

  vector<int> a;

   } ans[i][j] 记录前i朵花放入前j个花瓶得到最大美学值时的放置方案,

将转移方程dp[i][j] = max(dp[i][j-1], dp[i-1][j-1] + a[i][j])拆分为if...else...来分情况处理,记录放置方案的更新和转移,具体参考代码:

100分代码-动态规划:

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

const int N = 105;
int f, v;
int a[N][N];
int dp[N][N]; //dp[i][j]表示前i朵花放入前j个花瓶的最大美学值
struct node 
{
    vector<int> a;
} ans[N][N]; //ans[i][j]记录前i朵花放入前j个花瓶得到最大美学值时的放置方案


int main()
{
    cin >> f >> v;
    for(int i = 1; i <= f; i++)
        for(int j = 1; j <= v; j++)
            cin >> a[i][j];
    
    memset(dp, -0x3f, sizeof(dp)); //初始化
    for(int j = 0; j <= v; j++) dp[0][j] = 0; //0朵花放j个花瓶的美学值是0

    for(int i = 1; i <= f; i++)
    {
        for(int j = i; j <= v; j++) //花瓶号不可能小于花的编号
        {
            if(dp[i-1][j-1] + a[i][j] > dp[i][j-1]) //第i朵花放第j个花瓶
            {
                dp[i][j] = dp[i-1][j-1] + a[i][j];
                //把i-1,j-1的方案拷贝到i,j的方案
                for(int v : ans[i-1][j-1].a)
                {
                    ans[i][j].a.push_back(v);
                }
                //i,j的方案再加上i放入第j个花瓶
                ans[i][j].a.push_back(j);
            }
            else //第i朵花不放第j个花瓶
            {
                dp[i][j] = dp[i][j-1];
                //把i,j-1的方案拷贝到i,j的方案
                for(int v : ans[i][j-1].a)
                {
                    ans[i][j].a.push_back(v);
                }
            }
        }
    }

    cout << dp[f][v] << endl;
    for(int v : ans[f][v].a) cout << v << " ";
    
    return 0;
}

 

标签:花店,花瓶,int,洛谷题,朵花,美学,ans,P1854,dp
From: https://www.cnblogs.com/jcwy/p/18175057

相关文章

  • 洛谷题单指南-动态规划2-P1435 [IOI2000] 回文字串
    原题链接:https://www.luogu.com.cn/problem/P1435解题思路:方法1:回文字串的特点是,正着读、反着读是一样的换一个思路,对于一个字符串s,正序、逆序公共的部分就是已经是回文的部分,剩余的部分就是要插入的字符所以,问题转换为,计算一个字符串正序、逆序的最长公共子串,然后剩下的长度......
  • 洛谷题单指南-动态规划2-P1091 [NOIP2004 提高组] 合唱队形
    原题链接:https://www.luogu.com.cn/problem/P1091题意解读:要挑选一个最长的先上升后下降的序列,求其余的元素数量解题思路:先计算正向的最长上升子序列,设f[i]表示以i结尾的正向最长上升子序列再计算逆向的最长上升子序列,设g[i]表示以i结尾的逆向最长上升子序列再枚举所有的i<j,m......
  • 洛谷题单指南-动态规划2-P1004 [NOIP2000 提高组] 方格取数
    原题链接:https://www.luogu.com.cn/problem/P1004题意解读:从起点走到终点,走两次,计算最大路径和,第一次走过的点数值变为0。解题思路:直观上思考,可以先从起点走到终点,计算最大路径和,并记录走过的所有点,然后把所有点的数值置为0,再从起点走到终点,计算最大路径和,把两次的最大路径......
  • 洛谷题单指南-动态规划2-P2679 [NOIP2015 提高组] 子串
    原题链接:https://www.luogu.com.cn/problem/P2679题意解读:在a中按顺序挑选k个子串,使得这些子串连在一起正好和b相等,求方案数。解题思路:这样的题目,无外乎两个思路:DFS暴搜(得部分分)、动态规划动态规划不好想,还是先暴搜吧!1、DFS暴搜搜索的思路就是:从a起始位置开始,一直找到跟b前......
  • 洛谷题单指南-动态规划2-P1439 【模板】最长公共子序列
    原题链接:https://www.luogu.com.cn/problem/P1439题意解读:求最长公共子序列的长度。解题思路:1、O(n^2)的方法:动态规划设两个排列为a,b设dp[i][j]表示a[1~i]与b[1~j]的最长公共子序列长度根据公共子序列结尾是否包含a[i]、b[j]是否相等分情况讨论:如果a[i]==b[j]  则结尾......
  • 洛谷题解-官方题单-递归与递推
    P1255数楼梯原题链接题目描述楼梯有N阶,上楼可以一步上一阶,也可以一步上二阶。编一个程序,计算共有多少种不同的走法。对于60%的数据,N≤50;对于100%的数据,1≤N≤5000。思路:每次有2种方法上楼梯,要么上一阶,要么上二阶。第一种:得50分的做法是可以用递归来解:点击查看代码......
  • 洛谷题单指南-动态规划2-P2758 编辑距离
    原题链接:https://www.luogu.com.cn/problem/P2758题意解读:对a字符串最少操作几次可以变成b字符串,看似无从下手,可以从内部递推关系着手。解题思路:设dp[i][j]表示将a字符串1~i变成b字符串1~j的最少操作次数,字符串下标从1开始。如何思考递推?可以从最后一步为切入点!最后一步对a[i]......
  • 洛谷题单指南-动态规划2-P1874 快速求和
    原题链接:https://www.luogu.com.cn/problem/P1874题意解读:一个数字字符串s,分解成几个整数,和为n,计算最少加号个数,也就是计算最少分解的整数个数-1。解题思路:此题虽然分类在动态规划,但数据量不大,DFS更加直观和易于理解,所以采用DFS暴搜+剪枝来解决。搜索思路是对数字字符串依次枚......
  • 洛谷题单指南-动态规划2-P4933 大师
    原题链接:https://www.luogu.com.cn/problem/P4933题意解读:求有多少个子序列可以组成等差序列解题思路:1、暴力DFS如果实在想不出动规的方法,对于n<=20的数据,可以DFS枚举所有子序列的子集,再判断是否是等差数列。30分代码:#include<bits/stdc++.h>usingnamespacestd;const......
  • 洛谷题单指南-动态规划2-P1725 琪露诺
    原题链接:https://www.luogu.com.cn/problem/P1725题意解读:走过一系列格子之后,冰冻指数之和最大,相当于计算最大子序列的和。解题思路:设a[0~n]保存所有冰冻指数设dp[i]表示以第i号格子为终点所能获得的最大冰冻指数设j表示i的前一个格子,也就是从j可以移动到i已知i,则j的范围也......