sgu104

来源:互联网 发布:黎巴嫩真主党 知乎 编辑:程序博客网 时间:2024/05/18 10:33

SGU104 Little Shop Of Flowers

题目大意

你现在想用最令人满意的方案来装饰你花店的橱窗。你有 F 束 花, 每束花种类不同, 种数不超过窗台上的花瓶总数。花瓶被嵌入窗台,并且被顺序从1到 V 编号。V 表示花瓶总数。顺序编号使得1号花瓶在最左边, V 号花瓶在最右边。花束是可以移动的,而且按照不同种类从1 到 F 编 号。这些编号是有特殊含义的: 编号小的花必须出现在编号大的花的左边。现在,所有的花必须按编号顺序放在花瓶中,每个花瓶对应一种花。杜鹃花必须在秋海棠左面,秋海棠必须在康乃馨前面。如果花不够,将会有花瓶是空的.

每个花瓶都有自己的特征(就像花一样)。于是,把一种花放入一个花瓶会产生一定的 美学价值。用一个整数来表示美学价值,那么空花瓶的美学价值为0,花与花瓶搭配的美学价值如下表:

  花瓶      12345
  花束1 (杜鹃花)723-5-2416
      2 (秋海棠)521-41023
        3 (康乃馨)-215-4-2020


根据这个表,杜鹃花放在2号花瓶中会好看些,在4号花瓶中现得很别扭。 为了让方案最令人满意,你需要使美学价值最大化。如果有多种方案美学价值相同,选取任意一种都算对。你只需要算出 一种方案。

数据范围 • 1 ≤ F ≤ 100 表示花的种数。

• F ≤ V ≤ 100 表示花瓶数。

• -50 ≤ Aij ≤ 50 表示i号花束放入j号花瓶产生的美学价值。


输入 • 第一行: F, V.

• 接下来F行每行V个数,其中Aij 在第(i+1) 行第 j 列 。

输出 • 第一行包括一个整数表示最大美学价值。

• 第二行从左到右F个数表示最优方案的每个花束放在哪一个花瓶里,数据用空格隔开。

样例输入

3 5

7 23 -5 -24 16

5 21 -4 10 23

-21 5 -4 -20 20

样例输出

53

2 4 5


题目意思就是说要在每行取个数字,保证一个斜向右下角的序列,并且使这个序列和最大。

第一眼看出是动态规划

第二眼看还是动态规划。。。

这道题是基本的动态规划思路,由于F、V很小,时间复杂度O(F^2*V)也可以在0.5s内通过(当然我没有试过,因为莫名的PE问题)

这里我们有两种动归思路:


思路一:设F[i][j]——在取(i,j)的基础上对于(1,1)到(i,j)这个矩阵可以得到的最大序列和。

               显然:状态转移方程为:f[i][j]=max{f[i-1][k]+a[i][j]}(0<=k<j);

                          答案为:max{f[n][k]}(n<=k<m);

                          这种方法的优点:便于找寻路径(因为f[i][j]是必定取了(i,j)的)

                                            缺点:时间复杂度高,容易引起未知错误(据说SGU这题数据有问题,路径答案上有0的存在...,在Test1上PE了无数回。。。)


思路二:设F[i][j]——从(1,1)到(i,j)这个矩阵可以得到的最大序列和(不一定要取(i,j))

              状态转移方程为:f[i][j]=max{f[i-1][j-1]+a[i][j],f[i][j-1]};

              答案为:f[n][m];

              这种方法的优点:标准的背包思想很受欢迎,正确率高,时间复杂度较低O(F*V)

                                缺点:难得寻找路径(其实只需要一个判断数组check)


注意事项:1.如上面所说,这题数据好像有问题,因为在对路径输出中有0的存在,不过本人使用第一种方法要么在Test1上PE,要么在Test2上WA。。。

                  2.理论上,对于第i行,可取的数字范围为(i,i)~(i,V-F+i),但是这个优化加上之后程序就莫名其妙的PE了(也许这个理论是错误的,也许是弱渣的我代码能力渣,也许是题目数据本身有问题。)

                  3.总结一条刷SGU的潜规则:PE了不要怕,要么是自己代码WA了,要么就是评测机WA了。


下面附上我的代码:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>int a[110][110];int f[110][110];int check[110][110];int ans,ansk,n,m;void search(int i,int num){  int j;  if (i==0)    return ;  for (j=0;j<=m;j++)    if (num==f[i][j] && check[i][j])      {      search(i-1,num-a[i][j]);      printf("%d",j);      if (i==n)        printf("\n");      else        printf(" ");      break;      }  return ;}void init(){  int i,j,k;  scanf("%d%d",&n,&m);  for (i=1;i<=n;i++)    for (j=1;j<=m;j++)      scanf("%d",&a[i][j]);  for (i=1;i<=n;i++)    {    f[i][i]=f[i-1][i-1]+a[i][i];    check[i][i]=1;}  for (i=1;i<=n;i++)    for (j=i+1;j<=m;j++)      if (f[i-1][j-1]+a[i][j]>f[i][j-1])        {f[i][j]=f[i-1][j-1]+a[i][j];check[i][j]=1;}  else    f[i][j]=f[i][j-1];  printf("%d\n",f[n][m]);  search(n,f[n][m]);  return ;}int main(){  init();  return 0;}


0 0
原创粉丝点击