揹包練習

1、採藥(medic.pas/c/cpp)

【問題描述】

辰辰是個天資聰穎的孩子,他的夢想是成爲世界上最偉大的醫師。爲此,他想拜附近最有威望的醫師爲師。醫師爲了判斷他的資質,給他出了一個難題。醫師把他帶到一個到處都是草藥的山洞裏對他說:“孩子,這個山洞裏有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裏,你可以採到一些草藥。如果你是一個聰明的孩子,你應該可以讓採到的草藥的總價值最大。”

如果你是辰辰,你能完成這個任務嗎?


【輸入文件】

輸入文件medic.in的第一行有兩個整數T(1 <= T <= 1000)和M(1<= M <= 100),用一個空格隔開,T代表總共能夠用來採藥的時間,M代表山洞裏的草藥的數目。接下來的M行每行包括兩個在1到100之間(包括1和100)的整數,分別表示採摘某株草藥的時間和這株草藥的價值。

 

【輸出文件】

 

輸出文件medic.out包括一行,這一行只包含一個整數,表示在規定的時間內,可以採到的草藥的最大總價值。

 

【樣例輸入】

 

70 3

71 100

69 1

1 2

 

【樣例輸出】

 

3

 

【數據規模】

 

對於30%的數據,M<= 10;

對於全部的數據,M <= 100。

 【思路】經典的01揹包  這裏給出滾動數組和一維優化兩個版本

/*滾動數組*/ 
#include<cstdio>

int t,m,i,j;
int time[100],v[100];
int f[2][1001];

int main()
{
    freopen("medic.in","r",stdin);
    freopen("medic.out","w",stdout); 
    scanf("%d%d",&t,&m);
    for (i=0;i<m;i++) scanf("%d%d",&time[i],&v[i]);
    for (i=0;i<m;i++)
     {
       for (j=time[i];j<=t;j++)
         if (f[0][j-time[i]]+v[i]>f[1][j]) f[1][j]=f[0][j-time[i]]+v[i];
       for (j=0;j<=t;j++)  f[0][j]=f[1][j];    
       }
     printf("%d\n",f[0][t]);
     }  

/*一維*/ 
#include<cstdio>

int t,m,i,j;
int time[100],v[100];
int f[1001];

int main()
{
   freopen("medic.in","r",stdin);
    freopen("medic.out","w",stdout); 
    scanf("%d%d",&t,&m);
    for (i=0;i<m;i++) scanf("%d%d",&time[i],&v[i]);
    for (i=0;i<m;i++)
     {
       for (j=t;j>=time[i];j--)
        if (f[j-time[i]]+v[i]>f[j]) f[j]=f[j-time[i]]+v[i];
       }
     printf("%d",f[t]);
     }

2、裝箱問題(30分)(box.pas)

問題描述

有一個箱子容量爲V(正整數,0<=V<=20000),同時有n個物品(0<n<=30=,每個物品有一個體積(正整數)。

要求n個物品中,任取若干個裝入箱內,使箱子的剩餘空間爲最小。

輸入格式:一行數據,第一個整數,表示箱子容量,每二個整數,表示有n個物品,接下來n個數,分別表示這n 個物品的各自體積

輸出格式:一個整數,表示箱子剩餘空間。

樣例

輸入:(box.in)

24     6    8  3  12  7  9  7

輸出:(box.out)

0  一個整數,表示箱子剩餘空間。

【思路】01揹包,把V[I]當成體積也當成價值

#include<cstdio>

int vm,n,i,j;
int v[30],f[20000];

int main(){
    freopen("box.in","r",stdin);
    freopen("box.out","w",stdout);
    scanf("%d%d",&vm,&n);
    for (i=0;i<n;i++) scanf("%d",&v[i]);
    for (i=0;i<n;i++)
      for (j=vm;j>=v[i];j--)
       if (f[j-v[i]]+v[i]>f[j]) f[j]=f[j-v[i]]+v[i];
    printf("%d\n",vm-f[vm]);
}      
    

3、揹包問題(bag.pas)

設有n種物品,記作A1、A2、…、An,對應於每個Ai(1<=i<=n)都有一個重量Awi和價值Avi(重量和價值都爲正整數)。另外,對應於每個Ai,都有一件可代替它的“代用品”Bi,Bi的重量和價值分別爲Bwi和Bvi。本題的任務是:選擇這n件物品或其代用品的一個子集裝進揹包,使總重量不超過給定重量TOT,同時使總價值VAL最高。裝填的第i步,要麼裝入Ai,要麼裝入Bi,要麼Ai和Bi都不裝。

 

輸入數據:

從文件中讀取,文件的格式如下:

第一行:n  TOT   (n<1000,tot<100000)

第二行:Aw1  Av1  Bw1 Bv1

第三行:Aw2  Av2  Bw2 Bv2

            ……

第n+1行:Awn  Avn  BWn  BVn

 

輸出數據:

    輸出入文件中只有一個數值VAL

 

例如:

input.txt

2 10 

   3 6 2 3

6 9 5 10

 

output.txt

16

 

【思路】01揹包加強版,不同的是要多加一重判斷,裝A[I]較優還是B[I]較優

              注意要用臨時變量來更新F[I]的最優值,不然會出現裝了A[I]又裝B[I] (體積相等時)

              體積有可能爲0

#include<cstdio>

long n,tot,i,j;
long awi[1000],avi[1000],bwi[1000],bvi[1000],f[100000];


long Min(long a,long b) 
{
      if (a>b) return b; 
      return a;
      }

int main(){
    freopen("bag.in","r",stdin);
    freopen("bag.out","w",stdout);
    scanf("%ld%ld",&n,&tot);
    for (i=0;i<n;i++) scanf("%ld%ld%ld%ld",&awi[i],&avi[i],&bwi[i],&bvi[i]);
    for (i=0;i<n;i++)
      for (j=tot;j>=0;j--){  //j=0
        long max=f[j];
        if (j>=awi[i] && f[j-awi[i]]+avi[i]>max) max=f[j-awi[i]]+avi[i];//f[j]=f[j-awi[i]]+avi[i];
        if (j>=bwi[i] && f[j-bwi[i]]+bvi[i]>max) max=f[j-bwi[i]]+bvi[i];// f[j]=f[j-bwi[i]]+bvi[i];
        f[j]=max;
        }
     printf("%ld\n",f[tot]);
     }   


4、開心的金明

(happy.pas/c/cpp)

【問題描述】

金明今天很開心,家裏購置的新房就要領鑰匙了,新房裏有一間他自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎麼佈置,你說了算,只要不超過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]。(其中*爲乘號)

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

【輸入文件】

輸入文件happy.in 的第1行,爲兩個正整數,用一個空格隔開:

N m

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

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

v p

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

【輸出文件】

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

【輸入樣例】

1000 5

800 2

400 5

300 5

400 3

200 2

【輸出樣例】

3900

【思路】01揹包裸裸的

#include<cstdio>

int n,m,i,j;
int v[25],p[25];
long f[30000];

int main(){
    freopen("happy.in","r",stdin);
    freopen("happy.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (i=0;i<m;i++) scanf("%d%d",&v[i],&p[i]);
    for (i=0;i<m;i++)
     for (j=n;j>=v[i];j--)
      if (f[j-v[i]]+v[i]*p[i]>f[j]) f[j]=f[j-v[i]]+v[i]*p[i];
    printf("%ld\n",f[n]);
}

5、金明的預算方案

(budget.pas/c/cpp)

【問題描述】

金明今天很開心,家裏購置的新房就要領鑰匙了,新房裏有一間金明自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎麼佈置,你說了算,只要不超過N元錢就行”。今天一早,金明就開始做預算了,他把想買的物品分爲兩類:主件與附件,附件是從屬於某個主件的,下表就是一些主件與附件的例子:

主件

附件

電腦

打印機,掃描儀

書櫃

圖書

書桌

檯燈,文具

工作椅

如果要買歸類爲附件的物品,必須先買該附件所屬的主件。每個主件可以有0個、1個或2個附件。附件不再有從屬於自己的附件。金明想買的東西很多,肯定會超過媽媽限定的N元。於是,他把每件物品規定了一個重要度,分爲5等:用整數1~5表示,第5等最重要。他還從因特網上查到了每件物品的價格(都是10元的整數倍)。他希望在不超過N元(可以等於N元)的前提下,使每件物品的價格與重要度的乘積的總和最大。

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

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

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

【輸入文件】

輸入文件budget.in 的第1行,爲兩個正整數,用一個空格隔開:

N  m

(其中N(<32000)表示總錢數,m(<60)爲希望購買物品的個數。)

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

v  p  q

(其中v表示該物品的價格(v<10000),p表示該物品的重要度(1~5),q表示該物品是主件還是附件。如果q=0,表示該物品爲主件,如果q>0,表示該物品爲附件,q是所屬主件的編號)

【輸出文件】

輸出文件budget.out只有一個正整數,爲不超過總錢數的物品的價格與重要度乘積的總和的最大值(<200000)。

 

 

【輸入樣例】

1000 5

800 2 0

400 5 1

300 5 1

400 3 0

500 2 0

【輸出樣例】

2200

【思路】有依賴性的01揹包,由於附件只有0~2,可以轉成01揹包做,如果多個附件要用樹形動規

               一開始用二維數組存  讀入一直錯= =不知道什麼情況  換成一維的就正常了233

#include<cstdio>
#include<cstring>
int n,m,i,j,a,b,q;
long f[32000];
int v[60],w[60],v1[60],w1[60],v2[60],w2[60];

void Max(long a,long &b) { if (a>b) b=a; }

int main(){
    freopen("budget.in","r",stdin);
    freopen("budget.out","w",stdout);
    scanf("%d%d",&n,&m);
     for(i=1;i<=m;i++)
       {
            scanf("%d%d%d",&a,&b,&q);
            if(q)
            {
                    if(!v1[q]) {v1[q]=a;w1[q]=b;}
                    else {v2[q]=a;w2[q]=b;}
            }
            else {v[i]=a;w[i]=b;}
            }         
                        
    for (i=1; i<=m; i++)
		for (j=n; j>=0;j--)
		   { 
             if (j>=v[i]) Max(f[j-v[i]]+v[i]*w[i],f[j]);
			 if (j>=v[i]+v1[i]) Max(f[j-v[i]-v1[i]]+v[i]*w[i]+v1[i]*w1[i],f[j]);
			 if (j>=v[i]+v2[i]) Max(f[j-v[i]-v2[i]]+v[i]*w[i]+v2[i]*w2[i],f[j]);
			 if (j>=v[i]+v1[i]+v2[i]) Max(f[j-v[i]-v1[i]-v2[i]]+v[i]*w[i]+v1[i]*w1[i]+v2[i]*w2[i],f[j]);
			 }
	printf("%ld\n",f[n]);
}
	

6、 總分

學生在我們USACO的競賽中的得分越多我們越高興。
我們試着設計我們的競賽以便人們能儘可能的多得分,這需要你的幫助。
我們可以從幾個種類中選取競賽的題目,這裏的一個"種類"是指一個競賽題目的集合,解決集合中的題目需要相同多的時間並且能得到相同的分數。
你的任務是寫一個程序來告訴USACO的職員,應該從每一個種類中選取多少題目,使得解決題目的總耗時在競賽規定的時間裏並且總分最大。
輸入包括競賽的時間,M(1<= M <= 10,000)(不要擔心,你要到了訓練營中纔會有長時間的比賽)和N,"種類"的數目1 <= N <= 10,000。
後面的每一行將包括兩個整數來描述一個"種類":
第一個整數說明解決這種題目能得的分數(1 <= points <= 10000),第二整數說明解決這種題目所需的時間(1 <= minutes <= 10000)。
你的程序應該確定我們應該從每個"種類"中選多少道題目使得能在競賽的時間中得到最大的分數。
來自任意的"種類"的題目數目可能任何非負數(0或更多)。
計算可能得到的最大分數。

PROGRAMNAME: inflate

INPUTFORMAT

第 1 行:

M, N--競賽的時間和題目"種類"的數目。

第 2-N+1 行:

兩個整數:每個"種類"題目的分數和耗時。

SAMPLEINPUT (inflate.in)

300 4
100 60
250 120
120 100
35 20

OUTPUTFORMAT

單獨的一行包括那個在給定的限制裏可能得到的最大的分數。

SAMPLEOUTPUT ( inflate.out)

605
{從第2個"種類"中選兩題第4個"種類"中選三題}

【思路】完全揹包,注意優化後循環順序與01的區別

#include<cstdio>

int m,n,i,j,t,s;
long f[10000];

int main()
{
  freopen("inflate.in","r",stdin);
  freopen("inflate.out","w",stdout);
  scanf("%d%d",&m,&n);
  for (i=0;i<n;i++){
       scanf("%d%d",&s,&t);
       for (j=t;j<=m;j++)
	     if (f[j-t]+s>f[j]) f[j]=f[j-t]+s;
  }
  printf("%ld\n",f[m]);
}  

7、貨幣系統

母牛們不但創建了他們自己的政府而且選擇了建立了自己的貨幣系統。
[In their own rebellious way],,他們對貨幣的數值感到好奇。
傳統地,一個貨幣系統是由1,5,10,20或25,50, 和 100的單位面值組成的。
母牛想知道有多少種不同的方法來用貨幣系統中的貨幣來構造一個確定的數值。
舉例來說,使用一個貨幣系統 {1,2,5,10,...}產生 18單位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它。
寫一個程序來計算有多少種方法用給定的貨幣系統來構造一定數量的面值。
保證總數將會適合longlong (C/C++) 和 Int64 (Free Pascal)。

PROGRAMNAME: money

INPUTFORMAT

貨幣系統中貨幣的種類數目是 V 。 (1<= V<=25)
要構造的數量錢是 N 。 (1<= N<=10,000)

第 1 行:

 二整數, V 和 N

第 2 ..V+1行:

可用的貨幣 V 個整數 (每行一個 每行沒有其它的數)。

SAMPLE INPUT ( money.in)

3 10
1 2 5

OUTPUT FORMAT

單獨的一行包含那個可能的構造的方案數。

SAMPLE OUTPUT (money.out)

10


【思路】完全揹包求方案數:累加  (求最優值:max or min)
#include<cstdio>

int v,n,i,j;
int m[25];
long long f[10000];

int main()
{
  freopen("money.in","r",stdin);
  freopen("money.out","w",stdout);  
  scanf("%d%d",&v,&n);
  for (i=0;i<v;i++) scanf("%d",&m[i]);
  f[0]=1;////注意初始化 ,沒有這個全部都是0
  for (i=0;i<v;i++)
    for (j=m[i];j<=n;j++) f[j]+=f[j-m[i]]; //f[j]= 不用第i種的方案數+用上第i種的方案數 
  printf("%I64d\n",f[n]);
}  
		

  

8、質數和分解(prime.pas)

問題描述

任何大於1的自然數N都可以寫成若干個大於等於2且小於等N的質數之和表達式(包括只有一個數構成的和表達式的情況)並且可能有不止一種質數和的形式。例如,9的質數和表達式就有四種本質不同的形式:9=2+5+2=2+3+2+2=3+3+3=2+7。

這裏所謂兩個本質相同的表達式是指可以通過交換其中一個表達式中參加和運算的各個數的位置而直接得到另一個表達式。

試編程求解自然數N可以寫成多少種本質不同的質數和表達式。

{輸入格式}

一個自然熟N, 2〈=2N〈=200。

(輸出格式)

N的本質不同的質數和表達式的數目。

{輸入樣例}prime.in

2

{輸出樣例}prime.out

1

{輸入樣例}prime.in

200

{輸出樣例}prime.out

9845164

 

 【思路】完全揹包求方案數,一開始打質數表打錯了= =

#include<cstdio>
#include<cmath>
#include<cstring>
const int MAXP=200;
int tot=0,n;
int prime[100];
long long f[200];


void searchprime(){
    prime[0]=2;
	tot++;
     for (int i=3;i<=MAXP;i++)
     {  bool b=true;
	    for (int j=2;j<=sqrt(i);j++)
		  if (i%j==0) { b=false; break; }
		if (b)  prime[tot++]=i;
        }
}		

int main(){
   freopen("prime.in","r",stdin);
   freopen("prime.out","w",stdout);  
   scanf("%d",&n);
   searchprime();
   memset(f,0,sizeof(f));
   f[0]=1; 
   for (int i=0;i<tot;i++) 
   { if (prime[i]>n) break;
     for (int j=prime[i];j<=n;j++)
	   f[j]+=f[j-prime[i]];}
	printf("%I64d\n",f[n]);
}	


9、最小乘車費用(busses.pas)

{問題描述}

某條街上每一公里就有一汽車站,乘車費用如下表

公里

1

2

3

4

5

6

7

8

9

10

費用

12

21

31

40

49

58

69

79

90

101

而一輛汽車從不行駛超過10公里。某人想行駛N公里,假使他可以任意次換車,請你幫他找到一種乘車方案使費用最小(10公里的費用比1公里小的情況是允許的)。

編一程序:從文件busses.in中讀入對乘車費用的描述:算出最小的價格;把結果寫入文件busses.out中。

{輸入文件}

第一行爲10個不超過100的整數,依次表示1~10公里的費用,相鄰兩數間用空格隔開。第二行爲某人想要行駛的公里數。

{輸出文件}

僅一行,包含一個整數,表示該測試點的最小費用。

{輸入樣例}busses.in

12      21  31  40 49  58  69  79  90  101

15

{輸出樣例}busses.out

147


【思路】完全揹包,注意數組開的時候多開一個,因爲這個讀入出問題調了好久2333

              求最小值時初始化F[0]=0,其他設爲∞

#include<iostream>
using namespace std;

int f[1000],cost[11];
int i,j,n;

int main(){
    freopen("busses.in","r",stdin);
    freopen("busses.out","w",stdout);
    for (i=1;i<=10;i++)  cin>>cost[i];  
    cin>>n;
    for (i=1;i<=n;i++)f[i]=99999;
    f[0]=0;
      for (i=1;i<=10;i++)
       for (j=i;j<=n;j++) 
        if ( f[j-i]+cost[i]<f[j]) f[j]=f[j-i]+cost[i];
     cout<<f[n]<<"\n";
     }   



10、砝碼稱重fama.pas

設有1g、2g、3g、5g、10g、20g的砝碼各若干枚(其總重<=1000),

要求:

    輸入方式:a1  a2  a3  a4  a5  a6

     (表示1g砝碼有a1個,2g砝碼有a2個,…,20g砝碼有a6個)

    輸出方式:Total=N

  (N表示用這些砝碼能稱出的不同重量的個數,但不包括一個砝碼也不用的情況)

如輸入:1_1_0_0_0_0   (注:下劃線表示空格)(fama.in)

 輸出:TOTAL=3  表示可以稱出1g,2g,3g三種不同的重量。(fama.out)


【思路】多重揹包轉化成01做,注意循環順序,但是碰到大數據會超時,要用二進制思想優化

/*01揹包做法*/ 
#include<cstdio>
#include<cstring>

const int w[7]={0,1,2,3,5,10,20};
long num[8],max=0,i,j,k;
bool f[205000];

int main(){
  freopen("fama.in","r",stdin);
  freopen("fama.out","w",stdout); 
  for (i=1;i<=6;i++)  {
     scanf("%ld",&num[i]);
	 max+=w[i]*num[i]; 
	 }
   memset(f,0,sizeof(f));
   f[0]=true;   
   for (i=1;i<=6;i++)
    for (k=1;k<=num[i];k++) //保證物品被用num[i]次 
	  for (j=max;j>=w[i]*k;j--) //保證不被重複累加 
        if (f[j-w[i]]) f[j]=true;
   int tot=0;
   for (i=1;i<=max;i++)  if (f[i]) ++tot;
   printf("%ld\n",tot);
}

11逃亡的準備

【問題描述】

在《Harry Potter the Deatly Hallows》中,Harry Potter他們在一起逃亡,現在有許多東西要放到赫敏的包裏面,但是包的大小有限,所以我們只能夠在裏面放入非常重要的物品,現在給出該種物品的數量、體積、價值的數值,希望你能算出怎麼樣能是揹包的價值最大的組合方式,並且輸出這個數值,赫敏會非常感謝你。

【輸入文件】hallows.in

第一行有2個整數,物品種數n和揹包裝載體積v。

2行到n+1行每行3個整數,爲第n種物品的數量m、體積w、價值s。

【輸出文件】hallows.out

輸出文件hallows.out僅包含一個整數,即爲能拿到的最大的物品價值總和。

【輸入樣例】            【輸出樣例】

2  10                     13

3           4  3

2           2  5

【註釋】

選第一種第一個,第二種兩個。結果爲3*1+5*2=13

【數據規模】

   對於30%的數據

1<=v<=500,1<=n<=2000,1<=m<=10,1<=w<=20,1<=s<=100

對於100%的數據

1<=v<=500,1<=n<=2000,1<=m<=5000,1<=w<=20,1<=s<=100


【思路】多重揹包 

 

#include<cstdio>

int n,v,i,j,k;
int num[2001],s[2001],w[2001];
long f[500];

int main()
{
   freopen("hallows.in","r",stdin);
   freopen("hallows.out","w",stdout); 
   scanf("%d%d",&n,&v);
   for (i=0;i<n;i++)  scanf("%d%d%d",&num[i],&w[i],&s[i]);
   for (i=0;i<n;i++)
     for (k=1;k<=num[i];k++)
       for (j=v;j>=k*w[i];j--)
          if (f[j-w[i]]+s[i]>f[j]) f[j]=f[j-w[i]]+s[i];
   printf("%ld\n",f[v]);
}  

二進制優化

/*多重揹包二進制優化*/ 
#include<cstdio>

int m,w,s,v,n,i;
int f[500];


void Zeroonepack(int value,int weight)
{
     int tj;
     for (tj=v;tj>=weight;tj--)
       if (f[tj-weight]+value>f[tj]) 
           f[tj]=f[tj-weight]+value;
           }
           

void MultiplePack(int num,int weight, int value)
{
  int k=1;
  while (k<num)
  {
     Zeroonepack(k*value,k*weight);
     num-=k;
     k*=2;
     }
   if (num) Zeroonepack(num*value,num*weight);
}     
     


12、打包

【問題描述】

你現在拿到了許多的禮物,你要把這些禮物放進袋子裏。你只有一個最多裝下V體積物品的袋子,你不能全部放進去。你也拿不動那麼重的東西。你估計你能拿的最大重量爲G。

    現在你瞭解了每一個物品的完美值、重量和體積,你當然想讓袋子中裝的物品的完美值總和最大,你又得計劃一下了。

【輸入】

第一行:V和G表示最大重量和體積。

第二行:N表示拿到N件禮物。

第三到N+2行:每行3個數Ti Vi Gi表示各禮物的完美值、重量和體積。

【輸出】

輸出共一個數,表示可能獲得的最大完美值。

【輸入輸出樣例】

輸入pack.in:

6 5

4

10 2 2

20 3 2

40 4 3

30 3 3

輸出 pack.out:

50

 

【數據規模】

對於20%的數據N,V,G,TiVi Gi<=10

對於50%的數據N,V,G,TiVi Gi<=100

對於80%的數據N,V,G,TiVi Gi<=300

80%到100%的數據是N,V,G,Ti Vi Gi<=380的離散隨機數據。

#include<cstdio>

int f[381][381];
int i,j,n,V,G,v,g,t,k;

int main()
{
   freopen("pack.in","r",stdin);
   freopen("pack.out","w",stdout); 
   scanf("%d%d",&V,&G);
   scanf("%d",&n);
   for (i=0;i<n;i++)
   {
      scanf("%d%d%d",&t,&v,&g);
	  for (j=V;j>=v;j--)
	    for (k=G;k>=g;k--)
		  if (f[j-v][k-g]+t>f[j][k]) f[j][k]=f[j-v][k-g]+t;
	}
	printf("%d\n",f[V][G]);
}
   


13、暗黑破壞神

【問題描述】

遊戲的主人公有n個魔法,每個魔法分爲若干個等級,第i個魔法有p[i]個等級(不包括0),每個魔法的每個等級都有一個效果值,一個j級的i種魔法的效果值爲w[I,j],魔法升一級需要一本相應的魔法書,購買魔法書需要金幣,第i個魔法的魔法書價格爲c[I],而小×只有m個金幣。

你的任務就是幫助小×決定如何購買魔法書才能使所有魔法的效果值之和最大,開始時所有魔法爲0級 效果值爲0。

【輸入格式】diablo.in

第一行  用空格的兩個整數 n,m。

以下n行,描述n個魔法,第i+1行描述第i個魔法。格式如下

c[i] p[i] w[i,1] w[i,2] … w[i,p[i]]

【輸出格式】diablo.out

第一行輸出一個整數,即最大效果值。

以後n行輸出你的方案。

第i+1行有一個整數v[i]表示你決定把第i個魔法學到v[i]級

如果有多解 輸出花費金幣最少的一組

如果還多解 輸出任意一組

【輸入輸出樣例】

diablo.in

diablo.out

3          10

1          3  1  2  2

2          3  2  4  6

3          3  2  1  10

11

1

0

3

 

 

 

 

 

 

【數據規模】

0<n<=100 , 0<m<=500 , 0<p[i]<=50 , 0<c[I]<=10

保證輸入數據和最終結果longint在範圍內。

#include<cstdio>

int w[101][51],mark[101][501],c[101],p[101];
int i,j,k,n,m;
int f[101][501];

void fenzupack()
{
    for (i=0;i<n;i++)
      for (j=0;j<=m;j++)//j coins
       { 
         f[i][j]=f[i-1][j];////!
         mark[i][j]=0;
         for (k=0;k<=p[i] && j>=k*c[i]; k++)
           if (f[i-1][j-c[i]*k]+w[i][k]>f[i][j]) 
            {  mark[i][j]=k;
               f[i][j]=f[i-1][j-c[i]*k]+w[i][k];
            }            
       }
}

void prt()
{
     int max=0,bestv,bestn;
     for (i=0;i<n;i++)
       for (j=m;j>=1;j--) //downto 
       if (f[i][j]>=max)
         {
            bestv=j;
            bestn=i;
            max=f[i][j];
            }
      j=bestv;
      int v[101];
      for (i=bestn;i>=0;i--)
           {
             v[i]=mark[i][j];
             j-=c[i]*v[i];
             }
      printf("%d\n",max);
      for (i=0;i<n;i++) printf("%d\n",v[i]);
}       
                                              
int main()
{
    freopen("diablo.in","r",stdin);
    freopen("diablo.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (i=0;i<n;i++) { scanf("%d%d",&c[i],&p[i]); for (j=1;j<=p[i];j++) scanf("%d",&w[i][j]);}
    fenzupack();
    prt();
     } 

14、科技莊園

描述Description

  【問題描述】(manor.pas)
Life種了一塊田,裏面種了有一些桃樹。
Life對PFT說:“我給你一定的時間去摘桃,你必須在規定的時間之內回到我面前,否則你摘的桃都要歸我吃!”
PFT思考了一會,最終答應了!
  由於PFT的數學不好!它並不知道怎樣才能在規定的時間獲得最大的價值,
  由於PFT不是機器人,所以他的體力並不是無限的,他不想摘很多的桃以至體力爲0,而白白把桃給Life。同時PFT每次只能摘一棵桃樹,,每棵桃樹都可以摘K次(對於同一棵桃每次摘的桃數相同)。每次摘完後都要返回出發點(PFT一次拿不了很多)即Life的所在地(0,0){試驗田左上角的桃座標是(1,1)}。
PFT每秒只能移動一個單位,每移動一個單位耗費體力1(摘取不花費時間和體力,但只限上下左右移動)。
【輸入數據】manor.in
  第一行:四個數爲N,M,TI,A 分別表示試驗田的長和寬,Life給PFT的時間,和PFT的體力。
  下面一個N行M列的矩陣桃田。表示每次每棵桃樹上能摘的桃數。
  接下來N行M列的矩陣,表示每棵桃最多可以採摘的次數K。
【輸出數據】manor.out
  一個數:PFT可以獲得的最大的桃個數。
【輸入樣例】
4 4 13 20
10 0 0 0
0 0 10 0
0 0 10 0
0 0 0 0
1 0 0 0
0 0 2 0
0 0 4 0
0 0 0 0
【輸出樣例】
10
【樣例解釋】
  可以摘到1次(1,1)和1次(2,3),體力和時間不滿足再摘桃了。
【數據範圍】
  對於M N TI A
 10<=30%<=50
 10<=100%<=100
  對於K
 10<=100%<=100
  保證結果在longint範圍內

 

 

#include<cstdio>
int i,j,A_,time,n,m,ti,a,k;
long peach[102][102]/*value*/,num[102][102],cost[102][102];
long f[102];

int main()
{
    freopen("manor.in","r",stdin);
    freopen("manor.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&ti,&a);
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
      {
        scanf("%ld",&peach[i][j]);
        if (peach[i][j]) cost[i][j]=(i+j)<<1;
        }
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        scanf("%ld",&num[i][j]);    
    if (ti>a-1)  ti=a-1;   //要留一個體力= =坑 
    for (i=1;i<=n;i++)
      for (j=1;j<=m;j++)
        if (peach[i][j]&& num[i][j])
          for (k=1;k<=num[i][j];k++) 
           for (time=ti;time>=k*cost[i][j];time--)
              if (f[time-cost[i][j]]+peach[i][j]>f[time])
                 f[time]=f[time-cost[i][j]]+peach[i][j]; // 注意這裏很容易寫錯成f[time-cost[i][j]*k] 上層循環K已經保證取K次    
    printf("%ld\n",f[ti]);
}
    

 

 

 

 

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章