BZOJphp
比較裸的狀壓DP。
剛開始寫麻煩惹...
\(f[i][s]\)表示考慮了前\(i\)家商店,所買物品狀態爲\(s\)的最小花費。
能夠寫求一遍必定去\(i\)商店的\(f[i]\)(\(f[i][s]=f[i-1][s]+dis[i]\)),而後再和不去\(i\)商店的\(f[i-1]\)取個\(\min\)。
複雜度是\(O(nm2^m)\)嗎...git
能夠優化,處理\(f[s]\)表示在某家商店買\(s\)集合的物品的最小代價。而後令\(g[s]\)表示考慮全部商店買\(s\)集合的最小代價,有\(g[s]=\min(f[s],g[s']+f[s\ \text{xor}\ s'])\)。
複雜度\(O(n2^m+3^m)\)。優化
//27452kb 5284ms #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define lb(x) (x&-x) #define gc() getchar() typedef long long LL; const int N=103,M=16; int dis[N],cost[N][M+1],f[N][(1<<M)+1],ref[(1<<M)+1]; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-48,c=gc()); return now; } int main() { int n=read(),m=read(),lim=(1<<m)-1; for(int i=0; i<m; ++i) ref[1<<i]=i; for(int i=1; i<=n; ++i) for(int j=(dis[i]=read(),0); j<m; ++j) cost[i][j]=read(); memset(f,0x3f,sizeof f), f[0][0]=0; for(int i=1; i<=n; ++i) { for(int s=0; s<=lim; ++s) f[i][s]=f[i-1][s]+dis[i]; for(int s=0; s<lim; ++s) { for(int ss=s^lim,j; ss; ss^=lb(ss)) { j=ref[lb(ss)]; f[i][s|(1<<j)]=std::min(f[i][s|(1<<j)],f[i][s]+cost[i][j]); } } for(int s=0; s<=lim; ++s) f[i][s]=std::min(f[i][s],f[i-1][s]); } printf("%d\n",f[n][lim]); return 0; }