二解<花店橱窗布置>

来源:互联网 发布:shell编程简单题 编辑:程序博客网 时间:2024/06/10 14:41

花店橱窗布置题目见洛谷:https://www.luogu.org/problem/show?pid=1854
一.记忆化搜索
  这个问题第一眼看上去,它就是一个当初深搜求组合数的方案数的变形,m个花瓶插n朵花,而且这几朵花的顺序先后顺序不变,求和最大.是否有点像m个数取n个数组合,这n个数保证小的在前,大的在后,只不过是输出方案数而非和呢.看看数据规模100以内,想想,裸搜是一定会TLE的,但还是大胆地搜试试,果然AC1个点,9个点超时。
  想想这道题既然可以用动规解决,那在搜的过程中用适当的数组记下搜索产生的过程最优值,即记忆化搜索的方式对搜索剪枝也一定可以完成。于是采用了一个数组rem[101][101]来记录搜索过程中的最优值。如果之前对该第k朵花放至第t个花瓶及下方搜索完毕过,则直接返回rem[k][t],否则以搜索所有可能的情况,记录下最优值至rem[k][t]里。
  以样例数据为例,记忆化搜索树图如下,辅助理解:
  Markdown

#include<iostream>#include<climits>#include<iomanip>using namespace std;int n,m;int flower[101][101];int rem[101][101],can[101][101];int dfs(int k,int t){        if(rem[k][t]!=0)  return rem[k][t] ;    if(k==n){        return rem[k][t] = flower[k][t];    }    int ansM=INT_MIN,temp=0;    for(int j = t+1;j<= m-(n-k)+1; j++){        temp = dfs(k+1,j) + flower[k][t];        if(ansM < temp){            ansM = temp;            can[k][t] = j;         }            }    rem[k][t] = ansM;    return ansM;    }int main(){    cin >> n >> m;    for(int i = 1; i<= n; i++)    {        for(int j = 1; j<= m; j++)            cin >> flower[i][j];     }        cout << dfs(0,0) << endl;    int x = INT_MIN,s=0;    s = can[0][0];    cout << s << " ";    for(int i = 1; i< n; i++)    {        cout << can[i][s] <<" ";        s = can[i][s];    }    cout << endl;    return 0;}

二.动态规划
Markdown
  如图,可以看到是一个有向无环图,题目要求的是这个图的最长路径,一个比较好的算法是动态规划.对于第i束花放至第j个花瓶时的可能产生的最美值,实际是前i-1束花放至第i-1 ~ j-1之间的最优值 + flower[i][j].因此可以以放入的花束个数为阶段,动态规划状态转移方程为:dp[i][j] = max(dp[i][j],dp[i-1][k] + flower[i][j]),并同时记录这个最大值由哪个k来更新的,方便后期输出方案.
详细程序如下:

#include<iostream>#include<climits>using namespace std;int n,m;int flower[101][101],dp[101][101];int ans = INT_MIN,d=0;int v[101],ansv[101];int pat[101][101];int main(){     cin >> n >> m;    for(int i = 1; i<= n; i++){        for(int j = 1; j<= m; j++)            cin >> flower[i][j];     }    for(int i = 1; i<= n; i++){        dp[1][i] = flower[1][i];    }    for(int i =2; i<= n; i++)  //i代表花束    {        for(int j = i; j <= m-(n-i);j++){            for(int k = i-1; k< j; k++){                if(dp[i][j] < dp[i-1][k] + flower[i][j])                {                    dp[i][j] = dp[i-1][k] + flower[i][j];                    pat[i][j] = k;                }            }        }    }     int s;    for(int i = n; i<=m; i++){        if(ans<dp[n][i]){            ans = dp[n][i];            s = i;          }           }    cout << ans << endl;    for(int i=n; i>= 1; i--){        v[i] = s;        s = pat[i][s];    }    for(int i=1 ;i <= n; i++){        cout << v[i] << " ";    }    return 0;}