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; }