情報オリンピックワンパス-1271-ダイバー

ダイバー

タイトル説明:

ダイバーはダイビングのために特別な機器を使用する必要があります。彼は2つのガスを備えたシリンダーを持っています。1つは酸素用、もう1つは窒素用です。ダイバーが深海に潜るには、さまざまな量の酸素と窒素が必要です。ダイバーには一定数のシリンダーがあります。各シリンダーには重量とガス容量があります。ダイバーは仕事を完了するために一定量の酸素と窒素を必要とします。彼が仕事を完了するために必要なシリンダーの最小総重量はどれくらいですか?
例:ダイバーには5つのシリンダーがあります。各行の3つの数値は次のとおりです。酸素と窒素の量(リットル)とシリンダーの重量:
3 36120
10 25 129
5 50250
1 45130
4
20119ダイバーが5リットルの酸素と60リットルを必要とする場合窒素の、総重量最小は249(1、2または4、5シリンダー)です。
あなたの仕事は、ダイバーが仕事を完了するために必要なシリンダー重量の最小値を計算することです。

入る:

最初の行には2つの整数m、nがあります(1≤m≤21、1≤n≤79)。それらは、それぞれに必要な酸素と窒素の量を示しています。
2行目は、シリンダーの数を表す整数k(1≤n≤1000)です。
次のk行、各行にはai、bi、ci(1≤ai≤21、1≤bi≤79、1≤ci≤800)の3つの
整数が含まれます。これらは、i番目のシリンダー内の酸素と窒素の容量とシリンダーの重量です。

出力:

1つの行にのみ整数が含まれます。整数は、ダイバーが作業を完了するために必要なシリンダーの重量の合計の最小値です。


アイデア:

これは実際には2次元のコストナップサック問題です。コストが1次元増加した場合、状態は1次元だけ増加する必要があります。これは、一般的なナップサック問題に変換されます。唯一の違いは、酸素と窒素が需要を超えると、それらは需要に直接等しくなることです。

ここではナップザック問題の詳細な説明は次のとおりです。の詳細な説明ナップザック問題

  • f [i] [v] [u]を、最初のiアイテムに2つの価格vとuが支払われたときに取得できる最大値とします。
    状態遷移方程式:f [i] [v] [u] = max(f [i] [v] [u]、f [i-1] [va [i]] [ub [i]] + c [i ])
  • 01ナップザックが1次元の問題に
    変換されると、2次元のf [v] [u] = max(f [v] [u]、f [va [i]] [ub [i ]] + c [i])

以下のコードを見てください

#include <iostream>
#include <cstring>
using namespace std;
int a[1005],b[1005],c[1005],dp[105][105];
int main()
{
    
    
	int m,n,k;
	cin>>m>>n;
	cin>>k;
	for(int i=0;i<k;i++)
	{
    
    
		cin>>a[i]>>b[i]>>c[i];
	}
	memset(dp,127,sizeof(dp));//把f初始化为一个很大的整数
	dp[0][0]=0;//o2为0,n2为0时,重量为0 
	for(int i=0;i<k;i++)
	{
    
    
		for(int j=m;j>=0;j--)
		{
    
    
			for(int l=n;l>=0;l--)
			{
    
    
				int d1=j+a[i];//O2  和01背包不同,它的a[i]和b[i]是可以超过的
				int d2=l+b[i];//N2
				if(d1>m) d1=m;//若氮 和氧含量超过需求,直接等于需求
				if(d2>n) d2=n;
				dp[d1][d2]=min(dp[d1][d2],dp[j][l]+c[i]); 
			}
		}
	}
	cout<<dp[m][n]<<endl;
	
	return 0;
 }

おすすめ

転載: blog.csdn.net/weixin_45102820/article/details/114267649