博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ1837 Balance 背包
阅读量:5340 次
发布时间:2019-06-15

本文共 3165 字,大约阅读时间需要 10 分钟。

题目大意: 有一个天平,天平左右两边各有若干个钩子,总共有C个钩子(每个钩子有相对于中心的距离,左负右正),有G个钩码,求将钩码全部挂到钩子上使天平平衡的方法的总数。

将每个砝码看作一组,组内各个物品的体积为每个挂钩与该砝码形成的力矩,背包总体积严格为0,这便是分组背包计数问题(特殊点:每一组必须出一个物品,而不是至多出一个物品)。由于c++不允许负的数组下标,所以每次更新时,j要加上offsetJ。

实现分组背包计数问题时,可以用填表法(找以前节点求自己值)(DP1)或刷表法(找以后节点更新以后值)(DP2)。由于刷表法时,如果DP[i][j]==0,可以跳过,所以节省时间。

注意:

  • 不可以用一维数组倒序循环来表示DP数组,因为j-objV可能比j还大
  • 同理,每次判断时,不是j-objV>=0,0代表天平的支点而不是左端点。所以应当为j-objV>=minJ。
#include 
#include
#include
using namespace std;const int MAX_V = 16000, MAX_OBJ = 30, MAX_HOOP = 30;const int Plus = 7500;#define Sub(x) x+offsetJint TotHoop;int Len[MAX_HOOP], W[MAX_OBJ];void _printf(char *format, ...){#ifdef _DEBUG va_list(args); va_start(args, format); vprintf(format, args); va_end(args);#endif}int DP1(int totHoop, int totDev, int *_w, int *_len){ int minJ = 0, maxJ = 0, wSum = 0, offsetJ, objV = 0; static int DP[MAX_OBJ][MAX_V]; for (int dev = 1; dev <= totDev; dev++) wSum += _w[dev]; for (int hoop = 1; hoop <= totHoop; hoop++) _len[hoop] > 0 ? maxJ += _len[hoop] * wSum : minJ += _len[hoop] * wSum; offsetJ = -minJ; DP[0][offsetJ] = 1; _printf("+ offsetJ %d maxJ %d\n", +offsetJ, maxJ); for (int i = 1; i <= totDev; i++) for (int j = minJ; j <= maxJ; j++) for (int hoop = 1; hoop <= totHoop; hoop++) { objV = _w[i] * _len[hoop]; if (j - objV >= minJ && j - objV <= maxJ) { DP[i][j + offsetJ] += DP[(i - 1)][j + offsetJ - objV]; _printf("%d=DP[%d][%d] += DP[%d][%d]=%d\n", DP[i][j + offsetJ], i, j, i - 1, j - _w[i] * _len[hoop], DP[i - 1][j - _w[i] * _len[hoop] + offsetJ]); } } return DP[totDev][offsetJ];}int DP2(int totHoop, int totDev, int *_w, int *_len){ int minJ = 0, maxJ = 0, wSum = 0, offsetJ, objV = 0; static int DP[MAX_OBJ][MAX_V]; for (int dev = 1; dev <= totDev; dev++) wSum += _w[dev]; for (int hoop = 1; hoop <= totHoop; hoop++) _len[hoop] > 0 ? maxJ += _len[hoop] * wSum : minJ += _len[hoop] * wSum; offsetJ = -minJ; DP[0][offsetJ] = 1; _printf("+ offsetJ %d maxJ %d\n", + offsetJ, maxJ); for (int i = 0; i < totDev; i++) for (int j = minJ; j <= maxJ; j++) if (DP[i][j+ offsetJ]) for (int hoop = 1; hoop <= totHoop; hoop++) { objV = _w[i+1] * _len[hoop]; DP[i + 1][j + objV + offsetJ] += DP[i][j + offsetJ]; _printf("%d=DP[%d][%d] += DP[%d][%d]=%d\n", DP[i+1][j+objV+ offsetJ], i+1, j+objV+ offsetJ, i, j+ offsetJ , DP[i][j + offsetJ]); } return DP[totDev][offsetJ];}int main(){#ifdef _DEBUG freopen("c:\\noi\\source\\input.txt", "r", stdin);#endif int totDevice, vCnt = 0, totV = 0, maxV = 0, minV = 0; scanf("%d%d", &TotHoop, &totDevice); for (int i = 1; i <= TotHoop; i++) scanf("%d", i + Len); for (int i = 1; i <= totDevice; i++) scanf("%d", i + W); printf("%d\n", DP2(TotHoop, totDevice, W, Len)); return 0;}
View Code

 

转载于:https://www.cnblogs.com/headboy2002/p/8511849.html

你可能感兴趣的文章
【算法】—— 随机音乐的播放算法
查看>>
mysql asyn 示例
查看>>
DataGrid 点击 获取 行 ID
查看>>
git 使用
查看>>
边框圆角方法
查看>>
asp.net WebApi自定义权限验证消息返回
查看>>
php中eval函数的危害与正确禁用方法
查看>>
20172315 2017-2018-2 《程序设计与数据结构》第十一周学习总结
查看>>
MySQL添加、修改、撤销用户数据库操作权限的一些记录
查看>>
C#中List和数组之间转换的方法
查看>>
ViewBag & ViewData
查看>>
关于谷歌浏览器Chrome正在处理请求的问题解决
查看>>
Git核心技术:在Ubuntu下部署Gitolite服务端
查看>>
平面波展开法总结
查看>>
建造者模式
查看>>
ArraySort--冒泡排序、选择排序、插入排序工具类demo
查看>>
composer 安装laravel
查看>>
8-EasyNetQ之Send & Receive
查看>>
Android反编译教程
查看>>
java重写LinkedList
查看>>