题目链接:https://vjudge.net/problem/POJ-1170
题意:输入n,表示有那种物品,接下来n行,每行a,b,c三个变量,a表示物品种类,b是物品数量,c代表物品的单价。接下来一个数字m,表示有m个套餐,接下来m行,每行一个数字k,表示有k对数字,后面接k对数字,分别是物品种类和物品数量,最后一个value代表这个套餐的价格(套餐价格一定比单独买这些东西的价格低)。现在要我们求出买上面所有东西所需要的最低价格。
分析数据会发现物品种类会超过5,每种物品数量不会超过5,所以可以用状态压缩,虽然我第一发是用完全背包加六个循环...
思路就是这样,具体看代码:
状压dp:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque>
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 50005
/*struct point{
int u,w; };
bool operator <(const point &s1,const point &s2)
{
if(s1.w!=s2.w)
return s1.w>s2.w;
else
return s1.u>s2.u;
}*/
map<int,int>mp;
int n,m,k,t,MAX;
int num[],value[],vis[maxn];//vis标记i这个数字是不是超出了物品最大数量
int bit[];
int dp[maxn];
struct node{
int state,value;//记录套餐的状态压缩的值和套餐价格
}item[];
int check(int a)//检查a这个数字是不是每一种物品数量都不超出数量限制
{
for(int i=;i<&&a;i++){
if(a%>num[i])
return false;
a/=;
}
return true;
}
int cal(int a)//计算状态压缩值a在不考虑套餐情况下需要的花费
{
int ans=;
for(int i=;i<&&a;i++){
ans+=(a%)*value[i];
a/=;
}
return ans;
}
void init()//把每一个状态在不考虑套餐是需要的花费1计算出来
{
memset(dp,,sizeof(dp));
for(int i=;i<=MAX;i++){
if(check(i))
{
vis[i]=;//表示i是可行的
dp[i]=cal(i);
}
}
}
int main()
{
bit[]=;
for(int i=;i<=;i++){
bit[i]=bit[i-]*;
}
while(scanf("%d",&n)!=EOF){
memset(num,,sizeof(num));
memset(vis,,sizeof(vis));
MAX=;
int id=,a,b,c;
mp.clear();
for(int i=;i<=n;i++){
scanf("%d%d%d",&a,&b,&c);
if(mp[a]==)
mp[a]=id++;//给物品编号
num[mp[a]]=b;
value[mp[a]]=c;
MAX+=b*bit[mp[a]];
}
scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%d",&k);
int state=;
for(int j=;j<=k;j++){
scanf("%d%d",&a,&b);
state+=b*bit[mp[a]];
}
item[i].state=state;
scanf("%d",&item[i].value);
}
init();
for(int i=;i<=m;i++){
for(int j=item[i].state;j<=MAX;j++){
if(vis[j]&&vis[j-item[i].state])//j和j-item[i].state都不超出限制
dp[j]=min(dp[j],dp[j-item[i].state]+item[i].value);
}
}
printf("%d\n",dp[MAX]);
}
return ;
}
六个循环的代码就不写了,傻乎乎啊。