[BZOJ4145/AMPPZ2014]The Prices

Description
你要购买\(m\)种物品各一件,一共有\(n\)家商店,你到第i家商店的路费为\(d_i\),在第\(i\)家商店购买第\(j\)种物品的费用为\(c_{(i,j)}\),求最小总费用。

Input
第一行包含两个正整数\(n,m(1\leqslant n\leqslant 100,1\leqslant m\leqslant 16)\),表示商店数和物品数。
接下来\(n\)行,每行第一个正整数\(d_i(1\leqslant d_i\leqslant 10^6)\)表示到第i家商店的路费,接下来\(m\)个正整数,依次表示\(c_{(i,j)}(1\leqslant c_{(i,j)}\leqslant 10^6)\)

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

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

Sample Output
16


状压dp做多了发现都是套路题。。。设f[i][sta]表示当前在第i个商店,买的物品状态为sta的花费。转移分两种:

  • \(f[i][sta]=f[i-1][sta]+d[i]\),这个表示不买东西,从之前的商店过来
  • \(f[i][sta]=f[i][sta^(1<<(j-1))]+v[i][j],(sta\&(1<<(j-1))==1)\),这个表示在当前商店里买了东西

注意一点,从之前的商店不一定是从第i-1个商店转移过来,因此我们在最后要令\(g[i][sta]=min{\sum\limits_{j=1}^i f[j][sta]}\),由于\(g[i][sta]只\)在第一个转移被用到,而且第二个转移只是\(f[i][]\)的内部转移,因此我们直接用f代替g也是可以的

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)	print(x/10);
	putchar(x%10+'0');
}
const int N=1e2,M=16;
int d[N+10],val[N+10][M+10];
int f[N+10][(1<<M)+10];
int main(){
	int n=read(),m=read();
	for (int i=1;i<=n;i++){
		d[i]=read();
		for (int j=1;j<=m;j++)	val[i][j]=read();
	}
	memset(f,63,sizeof(f));
	f[0][0]=0;
	for (int i=1;i<=n;i++){
		for (int sta=0;sta<1<<m;sta++){
			for (int j=1;j<=m;j++)
				if (sta&(1<<(j-1)))
					f[i][sta]=min(f[i][sta],f[i][sta^(1<<(j-1))]+val[i][j]);
			f[i][sta]=min(f[i][sta],f[i-1][sta]+d[i]);
		}
		for (int sta=0;sta<1<<m;sta++)	f[i][sta]=min(f[i][sta],f[i-1][sta]);
	}
	printf("%d\n",f[n][(1<<m)-1]);
	return 0;
}
posted @ 2018-09-16 19:57  Wolfycz  阅读(183)  评论(0编辑  收藏  举报