zoukankan      html  css  js  c++  java
  • BZOJ 4145 [AMPPZ2014]The Prices (状压DP)

    题意

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

    分析
    • 很容易定义出状态,f(i,s)f(i,s)表示到第ii行,买的物品情况为ss的最小费用。按照往常的套路是转移时枚举子集,但那样的时间复杂度是O(n3m)O(ncdot 3^m)太慢了,于是我们只需要现将上一次的所有f(i1,s)+d[i]f(i-1,s)+d[i]复制到f(i,s)f(i,s),然后在第ii行每一个数考虑取不取就行了。因为这一行可以不选,最后再与f(i1,s)f(i-1,s)取一个最小值。时间复杂度O(nm2m)O(nm2^m)
    AC代码
    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 105;
    const int MAXM = 16;
    const int MAXS = 65536;
    int n, m, d[MAXN], cost[MAXN][MAXM], f[2][MAXS];
    int main () {
    	scanf("%d%d", &n, &m);
    	for(int i = 0; i < n; ++i) {
    		scanf("%d", &d[i]);
    		for(int j = 0; j < m; ++j)
    			scanf("%d", &cost[i][j]);
    	}
    	int now = 0;
    	memset(f[now], 0x3f, sizeof f[now]); f[now][0] = 0;
    	for(int i = 0; i < n; ++i) { now ^= 1;
    		for(int state = 0; state < (1<<m); ++state)
    			f[now][state] = f[now^1][state] + d[i];
    		for(int j = 0; j < m; ++j)
    			for(int state = 1; state < (1<<m); ++state) if((state>>j)&1)
    				f[now][state] = min(f[now][state], f[now][state^(1<<j)] + cost[i][j]);
    		for(int state = 0; state < (1<<m); ++state)
    			f[now][state] = min(f[now][state], f[now^1][state]);
    	}
    	printf("%d
    ", f[now][(1<<m)-1]);
    }
    
  • 相关阅读:
    背包问题
    计蒜客lev3
    线段树BIT操作总结
    图论题收集
    Codeforces Round #607 (Div. 2) 训练总结及A-F题解
    2-sat 学习笔记
    洛谷 P3338 【ZJOI2014】力/BZOJ 3527 力 题解
    $noi.ac$ #51 array 题解
    洛谷 P3292 【SCOI2016】幸运数字/BZOJ 4568 幸运数字 题解
    洛谷 P5283 【十二省联考2019】异或粽子 题解
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039434.html
Copyright © 2011-2022 走看看