1. 程式人生 > >狀壓dp--bzoj4145: [AMPPZ2014]The Prices

狀壓dp--bzoj4145: [AMPPZ2014]The Prices

傳送門 狀壓dpdp,列舉子集n3mn3^m過不了 考慮轉移的時候,一開始先假設在這個商店買了,令f[i][s]=f[i1][s]+d[i]f[i][s]=f[i-1][s]+d[i] 然後列舉不在ss集合的物品進行轉移,最後讓f[i][s]=min(f[i][s],f[i1][s])f[i][s]=min(f[i][s],f[i-1][s]) 複雜度nm2mnm2^mbzojbzoj上是能過的

這種就是先假設做了某件事最後再看到底做不做哪個更優來降低複雜度的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 105
#define maxm 16
using namespace std;
int n,m,d[maxn],c[maxn][maxm],f[maxn][(1<<maxm)+5];

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9'
) f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(); return x*f; } int main(){ n=rd(); m=rd(); for(register int i=1;i<=n;i++) { d[i]=rd(); for(register int j=1;j<=m;j++) c[i][j]=rd(); } memset(f,0x3f,sizeof f); f[0][0]=0; for(register int i=1;i<=
n;i++){ for(register int j=0;j<(1<<m);j++) f[i][j]=f[i-1][j]+d[i]; for(register int j=0;j<(1<<m);j++) for(register int k=1;k<=m;k++) if(!(j&(1<<(k-1)))){ f[i][j|(1<<(k-1))]=min(f[i][j|(1<<(k-1))],f[i][j]+c[i][k]); } for(register int j=0;j<(1<<m);j++) f[i][j]=min(f[i-1][j],f[i][j]); } printf("%d\n",f[n][(1<<m)-1]); return 0; }