花店橱窗布置

题面:https://www.luogu.com.cn/problem/P1854

给定一个 n * v 的矩阵

要求从第一行走到第f行,每行取走一个数,

且该行所取的数必须必上一行所取的数的列数大 , 求所能取走的最大值

注意每一行所取走的数字的列数必须大于等该行的行号

因为必须给前面的花留下足够的花瓶



由此我们便可以很容易的得出状态转移方程

dp [ i ] [ j ] = max ( dp [ i-1 ] [ k ] ) + d [ i ] [ j ] ( k < j )

其中dp [ i ] [ j ] 表示从第一行走到第 i 行并取走该行第j个数所能取得的最大值

①用字符串数组保留方案

设置string数组 an [ i ] [ j ] , 在dp数组转移状态时也一起转移

我们知道string是可以直接相加的,那么转移的时候如果继承上一个状态更优

那字符数组就由上一个状态加上这次的选择,也就是

if(dp[i-1][q]+a[i][j]>dp[i][j])
{
    dp[i][j]=max(dp[i][j],dp[i-1][q]+a[i][j]);
    an[i][j]=an[i-1][q]+zhuan(j);//这次是放在了j位置
    //zhuan函数是把数字变成字符串的函数
}

完整代码

#include <iostream>
using namespace std;
int n,m;
int a[109][109];
int dp[109][109];
string an[109][109];
string zhuan(int s){
    string k,q;
    while(s){
        k+=(s%10+‘0‘);
        s/=10;
    }
    for(int i=k.length()-1;i>=0;i--)
        q+=k[i];
    q+=‘-‘;
    return q;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    }
    //第i种花放在j位置
    for(int i=1;i<=m;i++)    dp[1][i]=a[1][i],an[1][i]=zhuan(i);
    int maxn=0;
    for(int i=2;i<=n;i++)
    {
        for(int j=i;j<=m;j++)
        {
            for(int q=1;q<j;q++)
            {
                if(dp[i-1][q]+a[i][j]>dp[i][j])
                {
                    dp[i][j]=max(dp[i][j],dp[i-1][q]+a[i][j]);
                    an[i][j]=an[i-1][q]+zhuan(j);
                    //zhuan函数是把数字变成字符串的函数
                }
            }
        }
    }
    int num;
    for(int i=1;i<=m;i++)
    {
        if(maxn<dp[n][i])
        {
            num=i;
            maxn=max(maxn,dp[n][i]);
        }
    }
    cout<<maxn<<endl;
    for(int i=0;i<an[n][num].length();i++)
    {
        if(an[n][num][i]==‘-‘)    cout<<" ";
        else    cout<<an[n][num][i];
    }
} 

②用 int 数组保存方案

同样的,定义pre [ i ] [ j ] 为让 dp [ i ] [ j ] 最大时上一个状态选的什么

初始化没有上一个状态,所以指向自己

    for(int i=1;i<=m;i++)    dp[1][i]=a[1][i],pre[1][i]=i;

然后我们和dp数组一起转移就是了

输出方案的时候一路倒推回去

int ans[109],cnt=n;
    ans[n]=num;//最后一个pre记录不到,手动输入
    while(pre[cnt][num]!=num)
    {
        ans[cnt-1]=pre[cnt][num];
        num=pre[cnt][num],cnt--;
    }
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";

二、跑dijtls最长路(懂什么意思就行,错是肯定写错了)

暂时不是很懂,先贴下别人代码。

//楼下全是dp,那么来个最长路做法
//可以将这个看成一个以花为横,瓶为纵的表格从下向上找一条路径,上一排的位置必须小于下一排
//那么我们就可以连边去跑最长路了
//同时我们注意到需要记录路径
//那么这里就选dij好了(因为其他的不会记路径啊)
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#pragma GCC optimize(3)
#define re register
#define maxn 10001
#define maxw 800000
#define inf -99999999
using namespace std;
struct node
{
    int v,w,nxt;
}e[maxw];
int f,v,ans,num=1,end;
int head[maxn],d[maxn],r[maxn];
int a[101][101];
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,less<pii> > q;
inline int read()
{
    char c=getchar();
    int x=0;
    int r=1;
    while(c<‘0‘||c>‘9‘)
    {
        if(c==‘-‘) r=-1;
        c=getchar();
    }
    while(c>=‘0‘&&c<=‘9‘)
    {
        x=x*10+c-48;
        c=getchar();
    }
    return r*x;
}
inline void add_edge(int x,int y,int z)
{
    e[num].v=y;
    e[num].w=z;
    e[num].nxt=head[x];
    head[x]=num++;
}
inline void dijkstra(int s)
{
    for(re int i=1;i<=f*v;i++)
      d[i]=inf;
    d[s]=0;
    q.push(make_pair(d[s],s));
    while(q.size())
    {
        pii mid=q.top();
        q.pop();
        int k=mid.second;
        for(re int i=head[k];i;i=e[i].nxt)
        if(d[e[i].v]<d[k]+e[i].w)
        {
            d[e[i].v]=d[k]+e[i].w;
            q.push(make_pair(d[e[i].v],e[i].v));//很常规的松弛操作
            r[e[i].v]=k;//存一下前驱结点,用来找路径
        }
    }
}
void dfs(int i)
{
    if(i!=0) dfs(r[i]);
    if(i!=0) cout<<i%v<<" ";//dfs找出路径,再将点还原成二维
}
int main()
{
    f=read();
    v=read();
    for(re int i=1;i<=f;i++)
    for(re int j=1;j<=v;j++)
    a[i][j]=read();
    for(re int i=1;i<=v;i++)
      add_edge(0,i,a[1][i]);//我们把0作为起点,把第一列的所有点与0相连
    for(re int i=2;i<=f;i++)
    for(re int k=1;k<=v;k++)
    for(re int j=k+1;j<=v;j++)
      add_edge((i-2)*v+k,(i-1)*v+j,a[i][j]);//把点的坐标压成一维
      //连边,需要注意的是上一行点的横坐标要小于下一行的
    dijkstra(0);
    ans=inf;
    for(re int i=1;i<=v;i++)
    if(ans<d[(f-1)*v+i])//从最后一行找最长路
    {
        ans=d[(f-1)*v+i];
        end=(f-1)*v+i;
    }
    cout<<ans<<endl;
    dfs(r[end]);
    end%=v;
    if(end==0) end=v;
    cout<<end<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/iss-ue/p/12491921.html

时间: 2024-10-13 02:14:00

花店橱窗布置的相关文章

RQNOJ PID496/[IOI1999]花店橱窗布置

PID496 / [IOI1999]花店橱窗布置 ☆ 题目描述 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按1到V顺序 编号,V是花瓶的数目.花束可以移动,并且每束花用1到F的整数标识.如果I < J,则花束I必须放在花束J左边的花瓶中.例如,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有花束在放入花瓶时必须保持其标识 数的顺序,即杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中.如果

1028 花店橱窗布置

1028 花店橱窗布置 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 假设以最美观的方式布置花店的橱窗,有F束花,V个花瓶,我们用美学值(一个整数)表示每束花放入每个花瓶所产生的美学效果.为了取得最佳的美学效果,必须使花的摆放取得最大的美学值. 输入描述 Input Description 第一行为两个整数F,V(F<=V<=100) 接下来F行每行V个整数,第i行第j个数表示第i束花放入第j个花瓶的美学值. 输

P1854 花店橱窗布置

P1854 花店橱窗布置 题目描述 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按1到V顺序编号,V是花瓶的数目.花束可以移动,并且每束花用1到F的整数标识.如果I < J,则花束I必须放在花束J左边的花瓶中.例如,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有花束在放入花瓶时必须保持其标识数的顺序,即杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中.如果花瓶的数目大于花束的数目,则多余

codevs1028花店橱窗布置(费用流)

这几天刚学了费用流,找到了这道题来练一练手. 题目: 题目描述 Description 假设以最美观的方式布置花店的橱窗,有F束花,V个花瓶,我们用美学值(一个整数)表示每束花放入每个花瓶所产生的美学效果.为了取得最佳的美学效果,必须使花的摆放取得最大的美学值. 输入描述 Input Description 第一行为两个整数F,V(F<=V<=100) 接下来F行每行V个整数,第i行第j个数表示第i束花放入第j个花瓶的美学值. 输出描述 Output Description 一个整数,即最大美

洛谷 P1854 花店橱窗布置

题目描述 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按1到V顺序编号,V是花瓶的数目.花束可以移动,并且每束花用1到F的整数标识.如果I < J,则花束I必须放在花束J左边的花瓶中.例如,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有花束在放入花瓶时必须保持其标识数的顺序,即杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中.如果花瓶的数目大于花束的数目,则多余的花瓶必须空,即每个花瓶只

luogu P1854 花店橱窗布置

题目描述 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,从左到右按1到V顺序编号,V是花瓶的数目.花束可以移动,并且每束花用1到F的整数标识.如果I < J,则花束I必须放在花束J左边的花瓶中.例如,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有花束在放入花瓶时必须保持其标识数的顺序,即杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中.如果花瓶的数目大于花束的数目,则多余的花瓶必须空,即每个花瓶只

codevs 1028 花店橱窗布置 (KM)

/*裸地KM*/ #include<iostream> #include<cstdio> #include<cstring> #define maxn 110 #define inf 0x3f3f3f3f using namespace std; int n,m,ans,match[maxn],w[maxn][maxn],d; int fx[maxn],fy[maxn],lx[maxn],ly[maxn]; bool Dfs(int i) { fx[i]=1; for(

【Luogu】P1854花店橱窗布置(DP)

照例良心题目链接 此题使用f[i][j]表示前i束花放进前j个花瓶的时候的最大值.转移方程如下 f[i][j]=max(f[i][j-1],f[i-1][j-1]+que[i][j]) 其中que[i][j]表示第i束花放进第j个花瓶里的情况.有这个转移方程的原因是,每一束花在每一个花瓶里的情况只有两种:放进去了和没放进去.第一种f[i][j-1]就是没放进去,第二种 f[i-1][j-1]+que[i][j]就是放进去了的情况 特殊的,当i>=j时第一种情况不能成立 路径保存死活没想出来,最后

codevs 1028 花店橱窗布置

最大费用最大流.分为两个集合,流量为1,费用为给的值即可. #include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<cmath>#define maxv 202#define maxe 20005#define inf 12345678using namespace std;int ff,vv,g[maxv],prev[maxv],pree[maxv],

[luoguP1854] 花店橱窗布置(DP)

传送门 f[i][j] 表示前 i 盆花,放到前 j 个花盆中的最优解 pre[i][j] 记录前驱 代码 #include <cstdio> #include <cstring> #include <iostream> #define N 1001 #define max(x, y) ((x) > (y) ? (x) : (y)) int n, m, t; int a[N][N], f[N][N], pre[N][N], s[N]; inline int rea