2017年8月15日提高组T2 购买

123 篇文章 0 订阅

Description


BPM想要购买m种物品,每种物品只用购买一件。现在一共有n家商店,但走到第i家商店的路费为d[i],而在第i家商店购买第j种物品的花费为c[i,j]。问你最少需要花费多少钱。

Input


第一行包含两个正整数n,m,表示商店数和物品数。
接下来n行,每行先是一个正整数d[i],表示到第i家商店的路费。接下来m个正整数,依次表示c[i,j]。

Output


一行一个整数,表示最小花费。

Hint


对于前30%的数据,1<=n,m<=7
对于前100%的数据,1<=n<=100,1<=m<=16,d[i],c[i,j]<=1000000

Source


BY BPM

Solution


数据中m极小,考虑状压dp
设f[i][j]为前i物品取状态为j的最小花费
可以发现每家商店最多进去一次,即d[i]最多只需要计算一次,那么每次单独拎出来+d[i]即可

Code


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
#include <vector>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) (x)>(y)?(x):(y)
#define min(x, y) (x)<(y)?(x):(y)
#define ll long long
#define db double
#define INF 0x3f3f3f3f
#define N 101
#define M 17
#define L 1<<16|1
int f[2][L], c[N][M], d[N];
int main(void){
    int n, m;
    scanf("%d%d",&n,&m);
    rep(i, 1, n){
        scanf("%d",&d[i]);
        rep(j, 1, m){
            scanf("%d",&c[i][j]);
        }
    }
    fill(f, 31);
    f[0&1][0] = 0;
    int lim = (1 << m) - 1;
    rep(i, 1, n){
        rep(j, 0, (1 << m) - 1){
            f[i&1][j] = f[(i - 1)&1][j] + d[i];
        }
        rep(k, 1, m){
            rep(j, 0, lim){
                if (~j&(1<<k-1))
                    f[i&1][j|(1<<k-1)] = min(f[i&1][j|(1<<k-1)], f[i&1][j] + c[i][k]);
            }
        }
        rep(j, 0, lim){
            f[i&1][j] = min(f[i&1][j], f[(i - 1)&1][j]);
        }
    }
    printf("%d\n", f[n&1][lim]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值