【BZOJ4145】[AMPPZ2014]The Prices 状压dp

the prices

题目大意

你要购买 \(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

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

样例

输入

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

输出

16

大致思路

首先要理解对题意!!!,是每个物品都要买一份,而不是买m件物品就行,不要理解错题意了(我猜只有我一开始想错了吧...),再看数据范围,怎么看都是状压dp啊,用二进制的每一位来表示该产品是否买过,一层一层的向下一个状态退,最后判断一下最大值即可,转移就好了,其实思路并不难想,代码也不难写,自己思考一下就能完成。\(dp[i][j]\)表示的是前i个店在j状态的最小值。

代码实现

#include
using namespace std;
const int maxn = (1 << 16) + 5;
int m,n,dp[105][maxn],a[105][20],d[105];
int Max;
void solve(){
	scanf("%d%d",&n,&m);
	Max = 1 << m;
	for(int i = 1; i <= n; i++){
		scanf("%d",&d[i]);
		for(int j = 1; j <= m; j++){
			scanf("%d",&a[i][j]);
		}
	}
	memset(dp,0x3f,sizeof(dp));
	dp[0][0] = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < Max; j++){
			dp[i][j] = dp[i-1][j] + d[i];
		}
		for(int k = 1; k <= m; k++){
			for(int j = 0; j < Max; j++){
				if(~j & (1 << k-1)){
					dp[i][j | (1 << k-1)] = min(dp[i][j | (1<

谢谢观看,喜欢的话点个关注~~

你可能感兴趣的:(【BZOJ4145】[AMPPZ2014]The Prices 状压dp)