zoukankan      html  css  js  c++  java
  • 花店橱窗布置

    题面: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 ] = max ( dp [ i-1 ] [ k ] ) + d [ i ] [ j ] ( k < j ) 

     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];
        }
    } 
    View Code

    用 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;
    }
    View Code
  • 相关阅读:
    c# 泛型委托
    c# 用户自定义转换
    c# 溢出上下文检测
    c# 接口相同方法申明使用
    c# 事件的订阅发布Demo
    c# 匿名方法几种表现形式
    c# 数组协变
    c# 交错数组
    C# 位运算详解
    ABAP 7.4 新语法-内嵌生命和内表操作(转)
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12491921.html
Copyright © 2011-2022 走看看