The Prices(有依赖性的状压dp)(去不同商店买东西先花不同路费)

The Prices 「BZOJ4145」

Decscription

你要购买(m)种物品各一件,一共有(n)家商店,你到第i家商店的路费为(d[i]),在第i家商店购买第j种物品的费用为(c[i][j]),求最小总费用。

Input

第一行包含两个正整数(n,m(1<=n<=100,1<=m<=16)),表示商店数和物品数。接下来(n)行,每行第一个正整数(d[i](1<=d[i]<=1000000))表示到第(i)家商店的路费,接下来m个正整数,依次表示(c[i][j](1<=c[i][j]<=1000000))

Output

一个正整数,即最小总费用。

Sample Input

3 4
5 7 3 7 9
2 1 20 3 2
8 1 20 1 1

Sample Output

16

Solution

这道题根据(m)的范围我们大概知道是状压dp,具体怎么实现的呢,我们还是要提前将路费加上,注意不能加重,之后类似于依赖背包。
具体解释看代码吧

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1<<16,Inf=0x3f3f3f3f;
int n,m,f[105][maxn],a[105][20],d[105];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&d[i]);
		for(int j=1;j<=m;++j){
			scanf("%d",&a[i][j]);
		}
	}
	int maxs=(1<<m)-1;
	for(int i=0;i<=n;++i){
		for(int j=0;j<=maxs;++j){
			f[i][j]=Inf;
		}
	}
	f[0][0]=0;
	for(int i=1;i<=n;++i){
		for(int j=0;j<=maxs;++j){//先付路费
			f[i][j]=f[i-1][j]+d[i];
		}//初始化完之后,不管j是多少,f[i][j]只有1个i的路费,这样避免不同的状态j加重路费
		for(int k=1;k<=m;++k){//后买东西
			for(int j=0;j<=maxs;++j){
				if(j&(1<<(k-1)))continue;
				f[i][j|(1<<(k-1))]=min(f[i][j|1<<(k-1)],f[i][j]+a[i][k]);
			}
		}
		for(int j=0;j<=maxs;++j){//决策在哪个商店
			f[i][j]=min(f[i][j],f[i-1][j]);//可以用本次循环的f[i][j]传递
		}
	}
	printf("%d
",f[n][maxs]);
	return 0;
}
原文地址:https://www.cnblogs.com/Lour688/p/13200934.html