bzoj 4145 [AMPPZ2014]The Prices dp

来源:互联网 发布:上海大陆期货交易软件 编辑:程序博客网 时间:2024/06/05 16:21

f[i][j]表示前i个商店买了j集合的物品的最小花费。
g[i][j] 表示第i个商店的买了j集合的物品的最小花费(含路费)。
注意到如果g[i][x]g[j][x] 那么去i买x的物品一定不比去j买x的物品差。
因此对于一种物品集合只需要有一个商店转移时转移这个集合就行。
复杂度O(n2m+3m)
其实也可以直接背包。。。

#include <bits/stdc++.h>using namespace std;#define N 110#define M (1<<16)+10int n,m;int d[N],c[N][21],pos[M];int g[N][M],f[N][M];int main(){    //freopen("tt.in","r",stdin);    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        scanf("%d",&d[i]);        for(int j=1;j<=m;j++)scanf("%d",&c[i][j]);        for(int j=1;j<1<<m;j++)        {            g[i][j]=d[i];            for(int k=0;k<m;k++)                if(j>>k&1)g[i][j]+=c[i][k+1];            if(!pos[j]||g[i][j]<g[pos[j]][j])                pos[j]=i;        }    }    memset(f,0x3f,sizeof(f));f[0][0]=0;    for(int i=1;i<=n;i++)    {        for(int j=0;j<1<<m;j++)            f[i][j]=f[i-1][j];        for(int j=1;j<1<<m;j++)            if(pos[j]==i)            {                int t=(1<<m)-1-j;                for(int k=t;;k=t&(k-1))                {                    f[i][j+k]=min(f[i][j+k],f[i-1][k]+g[i][j]);                    if(!k)break;                }            }    }    printf("%d\n",f[n][(1<<m)-1]);    return 0;}
0 0
原创粉丝点击