poj1018 动态规划

这篇博客介绍了如何利用动态规划解决poj1018问题,即寻找一套通讯系统中,使得带宽与价格比例最大的设备组合。通过动态规划算法,从每个供应商的设备中选择,更新最大带宽和总价格,最终得到最佳解决方案。例如,通过选取特定设备,得到了带宽为120,价格为185的组合,使得带宽价格比达到0.649。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:一套通讯系统由一些设备组成,每种设备由不同的供应商供应,每个供应商供应的同种设备有各自的带宽(bandwidth)和价格(prices)。通讯系统的带宽(B)指的是组成该系统的所有设备的带宽的最小值,通讯系统的价格(P)指的是组成该系统的所有设备的价格之和。求最大的 (B / P)。


算法:动态规划,由前i-1个供应商得到前i个供应商的情况 
定义 dp[i][j]=k 为前i个供应商、B=j时最小的P为k
那么,已知前i-1个供应商的情况,如何求i的情况? 
定义min_b为所有供应商中最小的B,max_b为最大的B 
对第i个供应商的每个设备j 
对dp[i-1][k] (min_b <= k <= max_b)
v[i][j][0] // 第i个供应商第j个设备的带宽 
v[i][j][1] // 第i个供应商第j个设备的价格 
t = min(k,v[i][j][0])
// 判断是否选择第i个供应商第j个设备
if (dp[i][t] < dp[i-1][k] + v[i][j][1])
{
dp[i][t] = dp[i-1][k] + v[i][j][1]
}

示例说明:
1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110


分别选择: 
1: 150 35
2: 155 40
3: 120 110 
B=120
P=185
B/P=0.649 


#include <iostream>
#include <stdio.h>
#include <math.h>
#include <limits.h>
using namespace std;

double dp[120][1200];	// dp[i][j] = k: 前i个供应商所能提供的设备,当最小带宽为j时,价格的最小和为k	 
int v[120][120][2];		// vp[i][j][0]、vp[i][j][1]: 分别表示第i个供应商的第j个设备的带宽和价格 
int d[120];				// dp[i] = j: 第i个供应商有j个相同的设备 


void init()
{
	for (int i=0; i<=120; i++)
	{
		for (int j=0; j<=1200; j++)
		{
			dp[i][j] = INT_MAX;
		}
	}
}


void solve(int n,int min_b, int max_b)
{
	// 枚举每个供应商 
	for (int i=2; i<=n; i++)
	{
		// 枚举第i个供应商的所有设备 
		for (int j=1; j<=d[i]; j++)
		{
			// 枚举i-1个供应商的所有情况,其min(B)的范围是(min_b,max_b),当然此范围是稍微放大的 
			for (int k=min_b; k<=max_b; k++)
			{
				int t = min(k,v[i][j][0]);
				if (dp[i][t] > dp[i-1][k]+v[i][j][1])
				{
					dp[i][t] = dp[i-1][k]+v[i][j][1];
				}
			}
		}
	}
}

int main()
{
	int t,n;
	int b,p;
	cin >> t;
	for (int i=0; i<t; i++)
	{
		init();
		double ans = -1;
		cin >> n;
		int min_b = INT_MAX;
		int max_b = -1;
		for (int j=1; j<=n; j++)
		{
			cin >> d[j];
			for (int k=1; k<=d[j]; k++)
			{
				cin >> v[j][k][0] >> v[j][k][1];
				min_b = min(min_b,v[j][k][0]);
				max_b = max(max_b,v[j][k][0]);
				if (j == 1)
				{
					dp[1][v[j][k][0]] = min(double(v[j][k][1]),dp[1][v[j][k][0]]);
				}
			}
		}
		
		solve(n,min_b,max_b);
		for (int j=min_b; j<=max_b; j++)
		{
			if (dp[n][j] > 0 && 1.0*j/dp[n][j] > ans)
			{
				ans = 1.0*j/dp[n][j];
			}
		}
		printf( "%.3f\n" , ans ) ;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kangwq2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值