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

原题链接: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;
}

 

posted @ 2024-05-06 15:11  五月江城  阅读(50)  评论(0编辑  收藏  举报