zoukankan      html  css  js  c++  java
  • 【bzoj4145】[AMPPZ2014]The Prices 状压dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6832200.html


    题目描述

    你要购买m种物品各一件,一共有n家商店,你到第i家商店的路费为d[i],在第i家商店购买第j种物品的费用为c[i][j],
    求最小总费用。

    输入

    第一行包含两个正整数n,m(1<=n<=100,1<=m<=16),表示商店数和物品数。
    接下来n行,每行第一个正整数d[i](1<=d[i]<=1000000)表示到第i家商店的路费,接下来m个正整数,
    依次表示c[i][j](1<=c[i][j]<=1000000)。

    输出

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

    样例输入

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

    样例输出

    16


    题解

    状态压缩dp

    设f[i][j]表示前i家商店购买状态为j时的最小总费用

    那么对于商店i,有去和不去两种情况。

    如果去,则先有f[i][j]=f[i-1][j]+d[i]。

    然后对于第k件物品,有买和不买两种情况,如果买,则f[i][j]=min(f[i][j],f[i][j^(1<<(k-1))]+c[i][k])(j&(1<<(k-1))!=0)

    如果不去,则f[i][j]=f[i-1][j]。

    发现可以先按照去来计算,最后和不去的情况取一个min就可以了。

    时间复杂度O(nm*2^m)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int d[110] , c[110][20] , f[110][66000];
    int main()
    {
    	int n , m , i , j , k;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%d" , &d[i]);
    		for(j = 1 ; j <= m ; j ++ ) scanf("%d" , &c[i][j]);
    	}
    	memset(f , 0x3f , sizeof(f));
    	f[0][0] = 0;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		for(j = 0 ; j < (1 << m) ; j ++ ) f[i][j] = f[i - 1][j] + d[i];
    		for(j = 0 ; j < (1 << m) ; j ++ )
    			for(k = 1 ; k <= m ; k ++ )
    				if(j & (1 << (k - 1)))
    					f[i][j] = min(f[i][j] , f[i][j ^ (1 << (k - 1))] + c[i][k]);
    		for(j = 0 ; j < (1 << m) ; j ++ ) f[i][j] = min(f[i][j] , f[i - 1][j]);
    	}
    	printf("%d
    ",  f[n][(1 << m) - 1]);
    	return 0;
    }

     

  • 相关阅读:
    前端与算法 leetcode 344. 反转字符串
    JavaScript闭包使用姿势指南
    前端与算法 leetcode 48. 旋转图像
    前端与算法 leetcode 36. 有效的数独
    前端与算法 leetcode 1. 两数之和
    前端与算法 leetcode 283. 移动零
    前端与编译原理 用js去运行js代码 js2run
    前端与算法 leetcode 66. 加一
    前端与算法 leetcode 350. 两个数组的交集 II
    前端与算法 leetcode 26. 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6832200.html
Copyright © 2011-2022 走看看