ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Jzoj P4224 食物___动态规划+多重背包

2019-01-26 20:04:25  阅读:312  来源: 互联网

标签:50000 ci Jzoj int P4224 max ___ include iii


题目大意:

nnn种食物,每种食物可以提供美味度tit_iti​,大小为uiu_iui​,有viv_ivi​份。
mmm种运输工具,每种运输工具每次可以大小总和运输xi≤x_i≤xi​的食物,单次花费yiy_iyi​,可以使用ziz_izi​次。
希望运输的食物的美味度总和p≥p≥p,且能提供的使用费用最大值为500005000050000,一份食物可以分成多块运输但是如果运输的不完整则不计美味度。
如果能够使美味度总和p≥p≥p,且花费50000≤50000≤50000,则求出最小花费,否则输出TATTATTAT

1n,m200,0p50000,1ti,ui,vi,xi,yi,zi1001≤n,m≤200,0≤p≤50000,1≤t_i,u_i,v_i,x_i,y_i,z_i≤1001≤n,m≤200,0≤p≤50000,1≤ti​,ui​,vi​,xi​,yi​,zi​≤100

分析:

SSS为美味度总和p≥p≥p时最小的食物大小总和,
则我们令dpidp_idpi​表示美味度总和为iii时,最小的食物大小总和,然后通过多重背包求得
注意iii的上界最大应该为p+max(t[])p+max(t_{[]})p+max(t[]​)
然后在S=min(dpi)S=min(dp_{i})S=min(dpi​) i[p,p+max(t[])]i∈[p,p+max(t_{[]})]i∈[p,p+max(t[]​)]
然后我们发现,因为可以分成多块运输,
问题就可以转化成在使得运输的总大小S≥S≥S时所需要的最小费用,
那我们可以设gig_igi​表示使用大小为iii时的最小花费,因为SSS可能非常大,所以我们可以交换一下位置,
gig_igi​表示花费iii的时候,所能得到的最大使用大小,那我们只需要求一个最小的费用iii满足最大使用大小S≥S≥S,iii的上界为费用使用最大值500005000050000,
那我们就可以也用多重背包来求解
因为这样的多重背包时间会很难受,所以我们可以通过二进制来进行优化
然后我们发现还是卡不过,可能需要单调队列的优化,
然后发现了有个可以过的方法,
对于后者,我们令ci,jc_{i,j}ci,j​表示选到了第iii种运输方式,花费了jjj时所能得到的最大使用大小,然后如果当前ci,jSc_{i,j}≥Sci,j​≥S,那么我们对于接下来的ci,j+1,..ci,50000c_{i,j+1},..c_{i,50000}ci,j+1​,..ci,50000​就可以剪枝掉。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>

#define N 205
#define M 50005
#define inf 0x3f3f3f3f

using namespace std;

struct Node { int t, u, v; }a[N];
struct Code { int x, y, z; }b[N];
struct Oier { int num, rv; }c[N*10];
struct Lier { int cost, v; }d[N*10];
int dp[N+M], g[N][M], n, m, p, T, cnt, tot;

void read(int &x)
{
	int f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9')   { if (s == '-')   f = -1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
	x = x * f;
}

int main()
{
	read(T);
	while (T--)
	{
        read(n); read(m); read(p);
        for (int i = 1; i <= p + 100; i++) dp[i] = inf; dp[0] = 0;
        cnt = 0;
		for (int i = 1; i <= n; i++) 
		{
		    read(a[i].t), read(a[i].u), read(a[i].v);
			for (int j = 1; j <= a[i].v; j <<= 1) 
                a[i].v -= j, c[++cnt].rv = a[i].u * j, c[cnt].num = a[i].t * j;
            if (a[i].v) c[++cnt].rv = a[i].u * a[i].v, c[cnt].num = a[i].t * a[i].v; 
		}
		for (int i = 1; i <= cnt; i++)
		    for (int j = p + 100; j >= c[i].num; j--) dp[j] = min(dp[j], dp[j - c[i].num] + c[i].rv);
	    int cdp = inf;
		for (int i = p; i <= p + 100; i++) cdp = min(cdp, dp[i]);
	
	    for (int i = 1; i <= m; i++) 
	        for (int j = 1; j <= 50000; j++) g[i][j] = 0;
	    tot = 0; 
		for (int i = 1; i <= m; i++) read(b[i].x), read(b[i].y), read(b[i].z);
	
		if (cdp == inf) 
	    {
	    	printf("TAT\n");
			 continue;
		}
		int check = inf;
	    for (int i = 1; i <= m; i++)
	        for (int j = 0; j <= b[i].z; j++)
	            for (int k = 1; k <= min(check, 50000); k++)
	                if (k >= b[i].y * j)
	                {
	                	g[i][k] = max(g[i][k], g[i - 1][k - b[i].y * j] + b[i].x * j); 
					    if (g[i][k] >= cdp) 
					    {
					        check = min(check, k);
					        break;
						}
					}   
		if (check == inf) printf("TAT\n"); else printf("%d\n", check);
	}
	return 0;
}

标签:50000,ci,Jzoj,int,P4224,max,___,include,iii
来源: https://blog.csdn.net/Gx_Man_VIP/article/details/86660425

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有