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\) 中的物品的最小代价。

于是转移的时候,如果决定要在 \(i\) 中买——那么先对所有状态加上路费,然后枚举每一个商品背包转移就可以了。



只写了我的做法。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I> inline void read(I &x) {
    int f = 0, c;
    while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    x = c & 15;
    while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    f ? x = -x : 0;
}

#define lowbit(x) ((x) & -(x))

const int N = 16 + 7;
const int M = 100 + 7;
const int NP = (1 << 16) + 7;

int m, n, S;
int a[M][N];
int f[NP], t[NP], dp[NP];

inline void ycl() {
    S = (1 << n) - 1;
    memset(f, 0x3f, sizeof(f));
    for (int i = 1; i <= m; ++i) {
        t[0] = a[i][0];
        for (int s = 1; s <= S; ++s) t[s] = t[s ^ lowbit(s)] + a[i][std::__lg(lowbit(s)) + 1];
        for (int s = 0; s <= S; ++s) smin(f[s], t[s]);
    }
}

inline void work() {
    ycl();
    memset(dp, 0x3f, sizeof(dp));
    dp[0] = 0;
    for (int s = 1; s <= S; ++s)
        for (int sta = s; sta; sta = (sta - 1) & s)
            smin(dp[s], f[sta] + dp[s ^ sta]);
    printf("%d\n", dp[S]);
}

inline void init() {
    read(m), read(n);
    for (int i = 1; i <= m; ++i)
        for (int j = 0; j <= n; ++j) read(a[i][j]);
}

int main() {
#ifdef hzhkk
    freopen("hkk.in", "r", stdin);
#endif
    init();
    work();
    fclose(stdin), fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/hankeke/p/bzoj4145.html

时间: 2024-08-29 07:35:23

bzoj4145 [AMPPZ2014]The Prices 状压 DP的相关文章

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个商店划不

【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 状压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

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

HDU5816 Hearthstone(状压DP)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collectible card game from Blizzard Entertainment. Strategies and luck are the most important factors in this game. When you suffer a desperate situation an

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <