HLG 1335 算法与追MM【多维背包】

Description
搞ACM不能只局限于看书和刷题,还要把它用到实际工作中,更是要把平时所学用到实际生活中去。
下面就是动态规划的经典运用!
 
你追一个MM的时候,需要对该MM身边的各闺中密友都好,这样你追MM这个问题就分解为对其MM朋友的问题,只有把这些问题都解决了,最终你才能追到MM。
该方法适用于聪明的MM,懂得“看一个人,不是看他如何对你,而是看他如何对他人。”的道理,并且对付这样的MM总能得到最优解。
该方法的缺点是开销较大,因为每个子问题都要好好对待。。。。
(如果是MM追GG,可以直接AC。)
 
所以,需要先把MM的朋友处理好,才能获得最终解。
 
GG需要获得MM朋友的好感,这样才有利于自己,但是要获得他们的好感不是那么容易的,需要拿点实际的讨好他们才行。
现在MM有n(1<=n<=100)个朋友,讨好第i个朋友获得的好感值为w[i](w[i]<=100000),但是为了讨好这个朋友,就必须付出m(1<=m<=5)种代价,比如请吃饭的代价、请帮忙的、请修电脑等等,并且每个人每种代价的花费是不一样的,所有代价都必须满足才能获得这个朋友的好感。
 
但是GG的m种代价每个最多有v[i]费用,并且v[i] <= 100000,v[1]*v[2]*..*v[m] <= 100000,他要怎样讨好MM的朋友才能获得最大的好感值。
 
Input
有多组测试数据。
对于每组测试数据,第一行为n, m,表示有n个朋友,有m种代价,第二行有m个代价的费用v[i]。
接下来有n行,每行有m+1个非负整数,第一个为这个朋友的好感值,剩下的m个数分别表示这个朋友需要的m种代价的花费。
处理到文件结束。
Output
每组测试数据输出一行,包含一个整数,表示获得的最大好感。
Sample Input
5 1
6
7 3
8 5
3 1
6 2
4 3
Sample Output

16

分析:  变进制数思想:
    给定一个正数序列,A1,A2,A3,A4,…..As;
  则以这个正数序列为进制的各位权为 P1 = A1+1,P2 = P1*(A2+1)………Ps=(P[s-1])*(As+1);添加P0 = 1;
    则这组正数序列在这组权下对应的数为V = A1*P0+A2*P1+A3*P2……..As*P[s-1];
    这样一组相关的正数序列可以合并为一个数来进行讨论,从而简化了背包容量的讨论。

View Code
#include<stdio.h>
#include<string.h>
#define max(a,b)(a)>(b)?(a):(b)
int p[10];
int v[7];
int f[100020];
int a[102];
int b[102][9];
int w[102];
int V;
int main()
{
    int i,j,k,tmp,n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=m;i++)
            scanf("%d",&v[i]);
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            for(j=1;j<=m;j++)
                scanf("%d",&b[i][j]);
        }
        p[0]=1;
        for(i=1;i<=m;i++)
            p[i]=p[i-1]*(v[i]+1);
        for(i=0;i<n;i++)
        {
            w[i]=0;
            for(j=1;j<=m;j++)
                w[i]+=p[j-1]*b[i][j];
        }
        for(i=1,V=0;i<=m;i++)
            V+=v[i]*p[i-1];
        int tot=0;
        memset(f,0,sizeof(f));
        for(i=0;i<n;i++)
        {
            tot=0;
            for(j=V;j-w[i]>=0;j--)
            {

                tot++;
                tmp=j;
                for(k=1;k<=m;k++)
                {
                    if(tmp%(v[k]+1)<b[i][k])
                       break;
                    tmp/=(v[k]+1);
                }
                if(k!=m+1)           // 如果状态不合法
                    continue;
                f[j]=max(f[j],f[j-w[i]]+a[i]);
            }
        }
        printf("%d\n",f[V]);
    }
    return 0;
}

 

posted @ 2012-04-21 23:33  'wind  阅读(440)  评论(0编辑  收藏  举报