SPOJ 247 chocolate (CHOCLO)

题目http://www.spoj.com/problems/CHOCOLA/

把一整块巧克力分成一个一个单元,掰断每一横行有个代价值,掰断每个纵行也有个代价值,要你求最后的总代价值最小

这个题目放在DP的题目列表里面,起初我是按DP的思想去解,先考虑只有一个单元的巧克力,再考虑2个单元,再是3个。。当把一个橫行都处理完再处理第二行,但是在处理第二行的时候就出问题了,到底此时是掰断橫行还是纵行,这里的操作会对之后造成影响,所以我这样,不是真正的最优子结构,因此这样DP就要出问题。后来发现原来直接贪心就可以了。

为了使总代价值最小,肯定要先掰断代价值最大的,这样使得那些代价值大的操作不会进行太多,因此结果肯定是最优的。所以先分别对 橫行代价值 与 纵行代价值 降序排序

在贪心过程中,需要注意一些细节,设置两个指针p q 分别指向此时橫行 和纵行 最大的代价值,每次比较这两个值,优先操作最大的,然后每次掰断了橫行的话,必定会引来一次纵行的全部拆散,反过来同样成立,。。。这个我也不知道怎么证明,不过确实是对的,。。其实我此刻靠在椅子上突然想明白为什么了,其实排序的过程,相当于把巧克力重新组合了一下,把价值大的横和纵 放在了最顶端 和 最右端,所以每次掰断相应的行列,就需要把那落单的一行 或者 一列 给全部拆解完! (这个是关键!)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1005
using namespace std;
bool cmp(int a,int b)
{
    return a>b;
}
int x[N],y[N];
int m,n;
int main()
{
   int t;
   int i,j;
   scanf("%d",&t);
   while (t--)
   {
       scanf("%d%d",&m,&n);
       for (i=1;i<m;i++)
       {
           scanf("%d",&x[i]);
       }
       for (i=1;i<n;i++)
       {
           scanf("%d",&y[i]);
       }
       sort(x+1,x+m,cmp);
       sort(y+1,y+n,cmp);
       int p=1,q=1,ans=0;
       while (p<=m-1 || q<=n-1)
       {
           if (p<=m-1 && x[p]>=y[q])
           {
               ans+=x[p];
               for (j=q;j<=n-1;j++) //每次掰出了一段,就拆解它 下面同理。
                 ans+=y[j];
               p++;
           }
           if (q<=n-1 && y[q]>x[p])
           {
               ans+=y[q];
               for (j=p;j<=m-1;j++)
                 ans+=x[j];
               q++;
           }
           if (p==m)
           {
               for (j=q;j<=n-1;j++)
                ans+=y[j];
               q=n;
           }
           if (q==n)
           {
               for (j=p;j<=m-1;j++)
                ans+=x[j];
               p=m;
           }
       }
       printf("%d
",ans);
   }
   return 0;
}
原文地址:https://www.cnblogs.com/kkrisen/p/3452752.html