1. 程式人生 > >洛谷——背包型dp

洛谷——背包型dp

ref 範圍 永遠 準備 amp 十分 das 遠的 自己

1.P1417 烹調方案

題目背景

由於你的幫助,火星只遭受了最小的損失。但gw懶得重建家園了,就造了一艘飛船飛向遙遠的earth星。不過飛船飛到一半,gw發現了一個很嚴重的問題:肚子餓了~

gw還是會做飯的,於是拿出了儲藏的食物準備填飽肚子。gw希望能在T時間內做出最美味的食物,但是這些食物美味程度的計算方式比較奇葩,於是絕望的gw只好求助於你了。

題目描述

一共有n件食材,每件食材有三個屬性,ai,bi和ci,如果在t時刻完成第i樣食材則得到ai-t*bi的美味指數,用第i件食材做飯要花去ci的時間。

眾所周知,gw的廚藝不怎麽樣,所以他需要你設計烹調方案使得美味指數最大

輸入輸出格式

輸入格式:

第一行是兩個正整數T和n,表示到達地球所需時間和食材個數。

下面一行n個整數,ai

下面一行n個整數,bi

下面一行n個整數,ci

輸出格式:

輸出最大美味指數

輸入輸出樣例

輸入樣例#1:
74 1
502
2
47
輸出樣例#1:
408

說明

【數據範圍】

對於40%的數據1<=n<=10

對於100%的數據1<=n<=50

所有數字均小於100,000

【題目來源】

tinylic改編

思路:

  如果沒有b[i]這個屬性的話就是明顯的01背包問題。

  現在考慮相鄰的兩個物品x,y。假設現在已經耗費p的時間,那麽分別列出先做x,y的代價:

  a[x]-(p+c[x])*b[x]+a[y]-(p+c[x]+c[y])*by

  a[y]-(p+c[y])*b[y]+a[x]-(p+c[y]+c[x])*bx

  對這兩個式子化簡,得到①>②的條件是c[x]*b[y]<c[y]*b[x].

  發現只要滿足這個條件的物品對(x,y),x在y前的代價永遠更優。

  因此可以根據這個條件進行排序,之後就是簡單的01背包了。

(づ ̄3 ̄)づ╭?~ 代碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
using
namespace std; int t,n; long long f[1000001],ans; struct Bag{ long long a,b,c; }eat[60]; int cmp(Bag X,Bag Y) { return Y.b*X.c < X.b*Y.c; } int main() { scanf("%d%d",&t,&n); for(int i=1; i<=n; i++) cin>>eat[i].a; for(int i=1; i<=n; i++) cin>>eat[i].b; for(int i=1; i<=n; i++) cin>>eat[i].c; sort(eat+1,eat+n+1,cmp); for(int i=1; i<=n; i++) { for(long long j=t; j>=eat[i].c; j--) { f[j]=max(f[j],f[j-eat[i].c]+eat[i].a-j*eat[i].b); } } for(int i=1; i<=t; i++) ans=max(ans,f[i]); cout<<ans<<endl; return 0; }

2.P1060 開心的金明

題目描述

金明今天很開心,家裏購置的新房就要領鑰匙了,新房裏有一間他自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎麽布置,你說了算,只要不超過N元錢就行”。今天一早金明就開始做預算,但是他想買的東西太多了,肯定會超過媽媽限定的N元。於是,他把每件物品規定了一個重要度,分為5等:用整數1~5表示,第5等最重要。他還從因特網上查到了每件物品的價格(都是整數元)。他希望在不超過N元(可以等於N元)的前提下,使每件物品的價格與重要度的乘積的總和最大。

設第j件物品的價格為v[j],重要度為w[j],共選中了k件物品,編號依次為j1,j2,……,jk,則所求的總和為:

v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*為乘號)

請你幫助金明設計一個滿足要求的購物單。

輸入輸出格式

輸入格式:

輸入的第1行,為兩個正整數,用一個空格隔開:

N m (其中N(<30000)表示總錢數,m(<25)為希望購買物品的個數。)

從第2行到第m+1行,第j行給出了編號為j-1的物品的基本數據,每行有2個非負整數

v p (其中v表示該物品的價格(v<=10000),p表示該物品的重要度(1~5))

輸出格式:

輸出只有一個正整數,為不超過總錢數的物品的價格與重要度乘積的總和的最大值(<100000000)。

輸入輸出樣例

輸入樣例#1:
1000 5
800 2
400 5
300 5
400 3
200 2
輸出樣例#1:
3900

說明

NOIP 2006 普及組 第二題

大水題一個 ~~~^_^~~~

(づ ̄3 ̄)づ╭?~ 代碼:

#include<iostream>
#include<cstdio>
using namespace std;

int n,m,v[30001],num[50];
int f[30001];

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++) {
        scanf("%d%d",&v[i],&num[i]);
    }
    for(int i=1; i<=m; i++) {
        for(int j=n;j>=v[i];j--) {
            f[j]=max(f[j],f[j-v[i]]+v[i]*num[i]);
        }
    }
    cout<<f[n]<<endl;
    return 0;
}

3.P1926 小書童——刷題大軍

題目背景

數學是火,點亮物理的燈;物理是燈,照亮化學的路;化學是路,通向生物的坑;生物是坑,埋葬學理的人。 文言是火,點亮歷史宮燈;歷史是燈,照亮社會之路;社會是路,通向哲學大坑;哲學是坑,埋葬文科生。——小A

題目描述

小A“刷題”十分猖狂,明目張膽地“刷題”。他現在在小書童裏發現了n樣他喜歡的“題目”,每“題”都有他的需要時間,而老師布置了m項作業,每項作業都有它的需要時間及分值,老師規定k分以上算及格。小A只剩r個單位時間,他想在及格的基礎上更多地“刷題”。

輸入輸出格式

輸入格式:

第一行:n m k r。第二行:n個數,代表每“題”他的需要時間。第三行:m個數。表示每項作業它的需要時間。第四行:m個數。代表每項作業它的分值。

輸出格式:

一個數,代表小A能刷幾道題

輸入輸出樣例

輸入樣例#1:
3 4 20 100
15 20 50
10 15 40 40
5 5 10 15
輸出樣例#1:
2

說明

沒有不能及格的情況

思路:

  用01背包求出做老師布置作業的最大分數,因為小A想要盡可能的多刷題,所以在老師布置作業一旦幾個以後立馬停止,剩余時間都用來刷題,要求刷題數目,所以從刷題所需時間最小的開始(排序)。。。

(づ ̄3 ̄)づ╭?~ 代碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n,m,k,r,tim;
int ti[10001],tm[10001],fs[10001];
int f[10001];

int main() {
    scanf("%d%d%d%d",&n,&m,&k,&r);
    for(int i=1; i<=n; i++) scanf("%d",&ti[i]);
    for(int i=1; i<=m; i++) scanf("%d",&tm[i]);
    for(int i=1; i<=m ;i++) scanf("%d",&fs[i]);
    for(int i=1; i<=m; i++) {
        for(int j=r; j>=tm[i]; j--) {
            f[j]=max(f[j],f[j-tm[i]]+fs[i]);
            
        }
    }
    for(int i=1; i<=r;i++)
        if(f[i]>=k) {
            tim=r-i;
            break;
        }
    sort(ti+1,ti+n+1);
    int i=0;
    while(tim>=ti[i+1]){
        i++;
        tim-=ti[i];
    }cout<<i<<endl;
    return 0;
}

自己選的路,跪著也要走完!!!

洛谷——背包型dp