BZOJ 4145: [AMPPZ2014]The Prices( 状压dp + 01背包 )

我自己只能想出O( n*3^m )的做法....肯定会T

O( nm*2^m )做法:

dp( x, s ) 表示考虑了前 x 个商店, 已买的东西的集合为s.

考虑转移 : 先假设我们到第x个商店去, so初始时 dp( x, s) = dp( x-1, s ) + d[x]

然后我们可以对第x个商店做01背包, dp(x, s + {h} ) = min( dp( x, s + {h} ) , dp( x, s) + c[x][h]) ) ( h ∉ s ).

之后我们再比较到第x个商店划不划算 : dp(x, s) = min(dp(x - 1, s) , dp(x, s) )

answer = dp(m, {1, 2, …… n } )

---------------------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<iostream>

#define rep(i, n) for(int i = 0; i < n; i++)

#define clr(x, c) memset(x, c, sizeof(x))

#define b(i) (1 <<(i))

using namespace std;

const int maxn = 105, maxm = 17, oo = int(1e9);

int d, c[maxm], dp[2][b(maxm)], A = 0, B = 1;

inline int read() {

char c = getchar();

for(; !isdigit(c); c = getchar());

int ans = 0;

for(; isdigit(c); c = getchar())

ans = ans * 10 + c - ‘0‘;

return ans;

}

int main() {

freopen("test.in", "r", stdin);

int n = read(), m = read(), all = b(m);

rep(s, all) dp[A][s] = oo;

dp[A][0] = 0;

rep(i, n) {

swap(A, B);

d = read();

rep(j, m) c[j] = read();

rep(s, all) dp[A][s] = dp[B][s] + d;

rep(j, m)

rep(s, all) if(!(s & b(j)))

dp[A][s | b(j)] = min(dp[A][s | b(j)], dp[A][s] + c[j]);

rep(s, all) dp[A][s] = min(dp[A][s], dp[B][s]);

}

printf("%d\n", dp[A][all - 1]);

return 0;

}

---------------------------------------------------------------------------------

4145: [AMPPZ2014]The Prices

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 156  Solved: 99
[Submit][Status][Discuss]

Description

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

HINT

在第一家店买2号物品,在第二家店买剩下的物品。

Source

鸣谢Claris上传

时间: 2024-11-09 10:57:02

BZOJ 4145: [AMPPZ2014]The Prices( 状压dp + 01背包 )的相关文章

BZOJ 4145 AMPPZ2014 The Prices 状压DP

题目大意:给定n个商店和m种物品,你需要每种物品买一个,去第i个商店的路费是di,第i个商店出售第j种物品的价格是ci,j,求最小花销 令fi,j表示当前已经考虑了前i个商店,购买的状态为j的最小花销 然后每个商店内跑个背包即可 时间复杂度O(nm2m) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int

poj 2923 状压dp+01背包

好牛b的思路 题意:一系列物品,用二辆车运送,求运送完所需的最小次数,两辆车必须一起走 解法为状态压缩DP+背包,本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品.预处理完能从枚举中找到tot个物品,再用这tol个物品中没有交集(也就是两个状态不能同时含有一个物品)的物品进行01背包,每个物品的体积是state[i],价值是1,求包含n个物品的最少价值也就是dp[(1<<n)-1](dp

bzoj4145 [AMPPZ2014]The Prices 状压 DP

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4145 题解 好像这道题有不少方法呢. ...谁叫这道题有点简单,所以方法多呗. 我的方法: 求出 \(f[S]\) 表示要在同一家商店购买 \(S\) 中的物品的最小代价. 然后 \(dp[S]\) 表示购买 \(S\) 中的商品的最小代价.枚举子集转移即可. 时间复杂度 \(O(m2^n+3^n)\). 还有一个不错的做法: \(dp[i][S]\) 表示在前 \(i\) 个商店买 \(S

【bzoj4145】[AMPPZ2014]The Prices 状压dp

原文地址:http://www.cnblogs.com/GXZlegend/p/6832200.html 题目描述 你要购买m种物品各一件,一共有n家商店,你到第i家商店的路费为d[i],在第i家商店购买第j种物品的费用为c[i][j], 求最小总费用. 输入 第一行包含两个正整数n,m(1<=n<=100,1<=m<=16),表示商店数和物品数. 接下来n行,每行第一个正整数d[i](1<=d[i]<=1000000)表示到第i家商店的路费,接下来m个正整数, 依次表

Bzoj 4145: [AMPPZ2014]The Prices

Bzoj 4145: [AMPPZ2014]The Prices 状态压缩dp \(f[i][j]\)表示前i个商店 , 状态为j的最小花费. 考虑什么东西也不买和买了东西. 买了东西的话,就要到i地. 然后转移:\(f[i][j] = min(f[i][j] , f[i][j ^ (1 << k - 1)] + c[i][k])\) 不买东西 \(f[i][j] = f[i - 1][j]\) /*header*/ #include <iostream> #include <

bzoj 1556: 墓地秘密【状压dp+spfa】

显然是状压,显然不可能把所有格子压起来 仔细观察发现只有机关周围的四个格子有用以及起点,所以我们用spfa处理出这些格子两两之间的距离(注意细节--这里写挂了好几次),然后设f[s][i]为碰完的机关石状态为s,现在在有用格子的第i个的最小停下次数,转移按照套路即可 #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const

BZOJ 4145 [AMPPZ2014] The Prices 解题报告

感觉也是一个小清新题.. 我们考虑设立状态 $Dp[i][s]$ 表示考虑了前 $i$ 个商店后,购买状态为 $s$ 的最小花费. 转移的话就枚举每个商店 $i$,首先令: $$Dp[i][s] = Dp[i - 1][s] + D[i]$$ 这个过程表示到达这个商店. 然后枚举每个状态 $s$,然后枚举每个不在 $s$ 里的物品 $j$,令: $$Dp[i][s + \{j\}] = min(Dp[i][s + \{j\}], Dp[i][s] + Cost[i][j])$$ 这个过程就相当于

BZOJ 1072 SCOI2007 排列perm 状压DP

题目大意:给定n个数字,求这些数字的全排列中有多少数能被d整除 令f[i][j]为状态为i,余数为j的方案数 枚举最高位转移 小心爆int #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,d,ans,f[1<<10][1<<10],digit[1<<10],tens[10

[BZOJ 1072] [SCOI2007] 排列perm 【状压DP】

题目链接:BZOJ 1072 这道题使用 C++ STL 的 next_permutation() 函数直接暴力就可以AC .(使用 Set 判断是否重复) 代码如下: #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <set>