vijos1426兴奋剂检查(多维费用的背包问题+状态压缩+hash)

背景

北京奥运会开幕了,这是中国人的骄傲和自豪,中国健儿在运动场上已经创造了一个又一个辉煌,super pig也不例外………………

描述

虽然兴奋剂是奥运会及其他重要比赛的禁药,是禁止服用的。但是运动员为了提高成绩难免要服用一些,super pig也不例外。为了不被尿检检查出来,这些药品就只能选一些不容易被发现的来服用。但是奥委会关于兴奋剂检查有很多个指标,只有尿检中各项数值均不高于规定指标才算成阴性(“你没服兴奋剂”),所以如何服用适量的药品使自己的水平达到最高是每个运动员困扰的问题。

现在有n个药品,每个药品如服用就必须全部用掉(否则会有副作用)。尿检检查共有m个项目,服用每个药品对于每个检查项目都会得到一定的效果值,这些效果值是累加的;服用每个药品当然还会给super pig一些水平提高值,这些效果也是累加的。现在super pig想把问题交给你来解决,因为吃药归吃药,训练才重要。

格式

输入格式

第一行有两个整数n (0<n<=200)和m (1<=m<=5),分别表示药品数和需要检查的项目;
第二行m个整数 v1---vm,表示检查各项目的指标(即最高不能超过的值);
第三行到第n+2行,分别是这n个药品的资料,每行m+1个数。每行第一个数表示服用该药品所得到的水平提高值,第二到第m+1个数分别表示服用这个药品每一项的效果值(分别对应第二行的指标类型)。

0<= k=1∏m Vk <=5000000

输出格式

一个整数,即super pig通过服这些药在不被检查出来的条件下所能得到的最高水平提高值

样例1

样例输入1[复制]

5 1
6
7 3
8 5
3 1
6 2
4 3

样例输出1[复制]

16

限制

各个测试点1s

按照我的惯例,先上搜索伪代码:

dfs(cur,v[],sum)
{
	if cur==n
	then
		record sum
		exit
	for(i->1 to m)
		if limit[i]-v[i]<w[i]
			exit
	dfs(cur+1,v[],sum)
	for(i->1 to m)
		v[i]->v[i]-w[i]
	dfs(cur+1,v[],sum+c[i])
}

当然,意识到此题是多维背包后,可以很容易地得出最简单的f[v1][v2][v3][v4][v5]的状态数组。

初始的转移方程就和经典的二维费用的方程差不多,只是多了几维。

然而由于0<=v<=5000000(范围有点问题),这样存储方式一定不行(不过,据说不加优化的背包也可以过哦)。

所以,要放个状态压缩。

(((a1(f[2]+1)+a2)(f[3]+1)+a3)(f[4]+1)+a4)(f[5]+1)+a5
a1,a2,a3,a4,a5代表当前5种药的各自取的量这一状态 ,而f[1~5]是每种药物的限制量

状态转移和上文说的呢,是差不多的

Accepted

 
100
511 4432 ksq2013 C++ 2016-08-19 20:28:29
#include<stdio.h>
#include<stdlib.h>
using namespace std;
inline int read()
{
    int x=0,c=getchar(),f=1;
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>47&&c<58)x=x*10+c-48,c=getchar();
    return x*f;
}
int n,m,ans,v[6],w[201][6];
int a1,a2,a3,a4,a5,f[1000001];
inline int hsh(int a,int b,int c,int d,int e)
{
    return (((a*(v[2]+1)+b)*(v[3]+1)+c)*(v[4]+1)+d)*(v[5]+1)+e;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
        v[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            w[i][j]=read();
    for(int i=1;i<=n;i++)
        for(a1=v[1];a1>=w[i][1];a1--)
            for(a2=v[2];a2>=w[i][2];a2--)
                for(a3=v[3];a3>=w[i][3];a3--)
                    for(a4=v[4];a4>=w[i][4];a4--)
                        for(a5=v[5];a5>=w[i][5];a5--){
                            int j=hsh(a1,a2,a3,a4,a5);
                            int k=hsh(a1-w[i][1],a2-w[i][2],a3-w[i][3],a4-w[i][4],a5-w[i][5]);
                            if(f[k]+w[i][0]>f[j]){
                                f[j]=f[k]+w[i][0];
                                if(f[j]>ans)
                                    ans=f[j];
                            }
                        }
    printf("%d
",ans);
    return 0;
}



原文地址:https://www.cnblogs.com/keshuqi/p/5957699.html