主頁 > 後端開發 > 背包問題(6):二維費用的背包問題

背包問題(6):二維費用的背包問題

2022-04-07 06:18:11 後端開發

        二維費用的背包問題是背包問題的一個簡單的常見擴展,

        二維費用的背包問題的一般描述為:對于裝入背包的每個物品i,都具有兩種不同的代價 C1[i]與C2[i],選擇物品i裝入背包時必須同時付出這兩種代價;對于每種代價都有一個可付出的最大值(上限)V1和V2,物品i裝入可獲得的價值為P[i],問在每個物品只能裝入一次的條件下,怎么選擇物品可得到最大的價值,

        其解題思路一般為:

        令 f[i][j][k]表示前i個物品在代價1為j,代價2為k的條件下裝入背包的可獲得的最大值,

        根據0/1背包問題有

            f[i][j][k] = max { f[i?1][j][k] , f[i?1][j?C1[i]][k?C2[i]] + P[i]}

        同樣可以將陣列由三維陣列優化為二維陣列,即

            f[j][k] = max { f[j][k] , f[j?C1[i]][k?C2[i]] + P[i]}

        撰寫代碼時,一般采用如下的3重回圈:

?         for (i=1;i<=n;i++)           // 裝入背包的物品個數為n

              for (j=V1;j>=C1[i];j--)

                     for (k=V2;k>=C2[i];k--)

                     {

                           f[j][k]=max(f[j][k],f[j-C1[i]][k-C2[i]]+P[i]);

                   }

        所求最大價值為f[V1][V2], 

【例1】游戲專案

問題描述

一天小明來到歡歡娛樂城游玩,游樂場的游戲專案真多呀,每個游戲專案需要花費小明的一些時間和一些金錢,

由于小明的時間和金錢是有限的,所以他很難將所有游戲專案都玩一遍,他決定選擇一些專案進行游玩,并且每個專案最多玩一次,他想知道在不超過自己所剩時間和金錢的范圍內,最多可以玩多少個游戲專案?

輸入

第一行三個整數n,M,T,表示一共有n(1≤n≤100)個游戲專案, 小明的手上還剩M(0≤M≤200)元,他有T(0≤T≤200)分鐘時間,

第2~n+1行 mi, ti 表示玩第i個游戲專案所需要的金錢和時間,

輸出

一行,一個數,表示小明最多可以玩的游戲專案的個數,

輸入樣例

6 10 10

1 1

2 3

3 2

2 5

5 2

4 3

輸出樣例

4

         (1)編程思路,

          玩游戲專案i時,需要付出的兩種代價分別為時間t[i]和金錢m[i],直接套用二維費用背包問題的模板即可,

          (2)源程式,

#include <stdio.h>
int max(int a,int b)
{
    if (a>b) return a;
    else  return b;
}
int main()
{
    int f[205][205]={0};
    int m[101],t[101];
    int n,M,T;
    scanf("%d%d%d",&n,&M,&T);
    int i,j,k;
    for (i=1;i<=n;i++)
    {
        scanf("%d%d",&m[i],&t[i]);
    }
    for (i=1;i<=n;i++)
      for (j=M;j>=m[i];j--)
        for (k=T;k>=t[i];k--)
        {
            f[j][k]=max(f[j][k],f[j-m[i]][k-t[i]]+1);
        }
    printf("%d\n",f[M][T]);
    return 0;
}

【例2】L國的戰斗之間諜

問題描述

L國即將與I國發動戰爭!!L國的指揮官想派出間諜前往I國,于是,選人作業就落到了你身上,

你現在有N個人選,每個人都有這樣一些資料:A(能得到多少資料)、B(偽裝能力有多差)、C(要多少工資),已知敵人的探查間諜能力為M(即去的所有人B的和要小于等于M)和手頭有X元錢,請問能拿到多少資料?

輸入

輸入第1行為三個整數:N、M、X(1≤N≤100,1≤M≤1000,1≤X≤1000),

之后有N行,每行包括三個整數:Ai、Bi、Ci,表示第i個人選相關資料,

輸出

能得到的資料總數,

輸入樣例

3 10 12

10 1 11

1 9 1

7 10 12

輸出樣例

11

          (1)編程思路,

         選擇第i個人選時,需要付出的兩種代價分別為偽裝能力b[i]和需要的經費c[i],選擇該人選后,可獲得的資料為a[i],直接套用二維費用背包問題的模板即可,

         (2)源程式,

#include <stdio.h>
int f[1001][1001]={0};
int main()
{
    int n,m,x;
    scanf("%d%d%d",&n,&m,&x);
    int a[101],b[101],c[101];
    int i,j,k;
    for (i=1;i<=n;i++)
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
    for (i=1;i<=n;i++)
    {
        for (j=m;j>=b[i];j--)
            for (k=x;k>=c[i];k--)
             if (f[j][k]<f[j-b[i]][k-c[i]]+a[i])
                f[j][k]=f[j-b[i]][k-c[i]]+a[i];
    }
    printf("%d\n",f[m][x]);
    return 0;
}

        將上面的源程式提交給洛谷題庫P1910 L國的戰斗之間諜(https://www.luogu.com.cn/problem/P1910),測評結果為Accepted

 【例3】三角牧場

問題描述

奶牛牧場建筑師I.M.Hei負責創建一個三角形的牧場,周圍有漂亮的白色圍欄,她被提供了N(3<=N<=40)個圍欄段,每個圍欄段的長度為整數Li(1<=Li<=40),她用這些圍欄段來組成三角形牧場的三條邊,使得該牧場的放牧面積最大,

輸入

第1行:單個整數N

第2行~N+1行:每行都有一個整數,表示一個圍欄段的長度,長度不一定是唯一的,

輸出

輸出一行為一個整數,該整數是最大可能封閉區域的面積乘以100的截斷整數表示,如果不能圍成三角形,則輸出-1,

輸入樣例

5

1

1

3

3

4

輸出樣例

692

         (1)編程思路,

        把邊的長度看成費用,三角形中的某條邊i看作第一維費用,另一條邊j看作是第二維費用,背包容量為總長sum的一半(三角形任意一條邊都不可能比周長的一半大),則第三邊為sum-i-j,給定的圍欄看成裝入背包的物品,

        設f[i][j]表示由這些圍欄是否可以構成一條邊長為i,另一條邊長為j,初始時除f[0][0]=1外,其余元素全部為0,

       通過二維0/1背包找出所有滿足的i,j(即f[i][j]=1),列舉求出最大面積即可,

        (2)源程式,

#include <stdio.h>
#include <string.h>
#include <math.h>
int f[805][805];
int main()
{
    int len[45];
    int n;
    while (scanf("%d",&n) !=EOF)
    {
        int sum=0;
        int i,j,k;
        for (i=1; i<=n; i++)
        {
           scanf("%d",&len[i]);
           sum+=len[i];
        }
        memset(f,0,sizeof(f));
        f[0][0]=1;
        int mid=sum/2;
        for (i=1; i<=n; i++)
           for (j=mid; j>=0; j--)
              for (k=mid; k>=0; k--)
              {
                  if ((j>=len[i]&& f[j-len[i]][k])||(k>=len[i]&&f[j][k-len[i]]))
                     f[j][k]=1;
              }
        int ans=-1;
        for (i=mid; i>0; i--)                       // 通過列舉可構成三角形的兩條邊,找到最大面積
           for (j=mid; j>0; j--)
              if (f[i][j])
              {
                  k=sum-i-j;                        // 第3條邊的長度
                  if (i+j>k && i+k>j && j+k>i)      // 兩邊之和大于第三邊
                  {
                      double p=sum/2.0;
                      double x=sqrt(p*(p-i)*(p-j)*(p-k));
                      if (x*100>ans)
                         ans=x*100;
                  }
              }
        printf("%d\n",ans);
    }
    return 0;
}

        將上面的源程式提交給北大OJ題庫POJ 1948 Triangular Pastures(http://poj.org/problem?id=1948),可以Accepted,

 【例4】鋪放線段

問題描述

有n條線段,每條線段只能放在數軸上的一個特定位置,并且第i根線段有如下幾個屬性:Xi(該線段放在數軸上的起點),Wi(該線段長度),Fi(你若使用該線段你能獲得的價值),Ci(你若使用該線段你所需要的費用),現在讓你從中選出一些線段,使得這些線段能夠鋪滿數軸上的區間[0,L],并且所花費用和不超過B,同時要使你識訓的價值盡量大,請你找到這個方案,

輸入

第一行三個整數 L(1 ≤L≤1,000),n(1≤N≤10,000),B(1 ≤B≤1,000),

接下來n行,每行四個整數 Xi,Wi,Fi,Ci,表示第i根線段的四個屬性,

輸出

一個整數,表示你能獲得的最大價值和,若無法滿足上述要求,則輸出?1,

輸入樣例

5 6 10

0 2 20 6

2 3 5 6

0 1 2 1

1 1 1 3

1 2 5 4

3 2 10 2

輸出樣例

17

        (1)編程思路,

        設f[i][j]表示選出的線段鋪滿數軸上的區間[0,i]且所花費用和不超過j時能識訓的最大價值,由于要鋪滿數軸上的區間[0,L],也就是背包的第1維得裝滿,因此初始時除f[0][0]=0外,其余元素均置為-1,f[i][j]=-1時,表示要鋪滿[0,i]區間不可能,因此,轉移是要保證轉移前的f[i’][j’]>=0,

        另外,需要對給定線段其放在數軸上的起點從小到大排個序,

         (2)源程式,

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int f[1005][1005];
struct Node
{
    int x,y,f,c;
};
int cmp(struct Node a,struct Node b)
{
    return a.x<b.x;
}
int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    memset(f,-1,sizeof(f));
    f[0][0]=0;
    int L,n,B;
    scanf("%d%d%d",&L,&n,&B);
    struct Node a[10005];
    int i,j;
    for (i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].f,&a[i].c);
        a[i].y+=a[i].x;
    }
    sort(a+1,a+n+1,cmp);
    for (i=1;i<=n;i++)
    {
        for (j=B;j>=a[i].c;j--){
            if(f[a[i].x][j-a[i].c]>=0)
            {
                f[a[i].y][j]=max(f[a[i].y][j],f[a[i].x][j-a[i].c]+a[i].f);
            }
        }
    }
    int ans=-1;
    for (i=1;i<=B;i++)
        ans=max(ans,f[L][i]);
    printf("%d",ans);
    return 0;
}

         將上面的源程式提交給洛谷題庫P2854 [USACO06DEC]Cow Roller Coaster S(https://www.luogu.com.cn/problem/P2854),測評結果為Accepted

【例5】寵物小精靈之收服

問題描述

寵物小精靈是一部講述小智和他的搭檔皮卡丘一起冒險的故事,

一天,小智和皮卡丘來到了小精靈狩獵場,里面有很多珍貴的野生寵物小精靈,小智也想收服其中的一些小精靈,然而,野生的小精靈并不那么容易被收服,對于每一個野生小精靈而言,小智可能需要使用很多個精靈球才能收服它,而在收服程序中,野生小精靈也會對皮卡丘造成一定的傷害(從而減少皮卡丘的體力),當皮卡丘的體力小于等于0時,小智就必須結束狩獵(因為他需要給皮卡丘療傷),而使得皮卡丘體力小于等于0的野生小精靈也不會被小智收服,當小智的精靈球用完時,狩獵也宣告結束,

我們假設小智遇到野生小精靈時有兩個選擇:收服它,或者離開它,如果小智選擇了收服,那么一定會扔出能夠收服該小精靈的精靈球,而皮卡丘也一定會受到相應的傷害;如果選擇離開它,那么小智不會損失精靈球,皮卡丘也不會損失體力,

小智的目標有兩個:主要目標是收服盡可能多的野生小精靈;如果可以收服的小精靈數量一樣,小智希望皮卡丘受到的傷害越小(剩余體力越大),因為他們還要繼續冒險,

現在已知小智的精靈球數量和皮卡丘的初始體力,已知每一個小精靈需要的用于收服的精靈球數目和它在被收服程序中會對皮卡丘造成的傷害數目,請問,小智該如何選擇收服哪些小精靈以達到他的目標呢?

輸入

輸入資料的第一行包含三個整數:N(0 < N < 1000),M(0 < M < 500),K(0 < K < 100),分別代表小智的精靈球數量、皮卡丘初始的體力值、野生小精靈的數量,

之后的K行,每一行代表一個野生小精靈,包括兩個整數:收服該小精靈需要的精靈球的數量,以及收服程序中對皮卡丘造成的傷害,

輸出

輸出為一行,包含兩個整數:C,R,分別表示最多收服C個小精靈,以及收服C個小精靈時皮卡丘的剩余體力值最多為R,

樣例輸入

輸入樣例

10 100 5

7 10

2 40

2 50

1 20

4 20

輸出樣例

3 30

           (1)編程思路,

        若收服某個小精靈需要的精靈球的數量超過了小智的精靈球數量或者收服程序中對皮卡丘造成的傷害超過了皮卡丘初始的體力值,則該小精靈不可能被收服,輸入時對資料進行預處理,將不可能收服的小精靈忽略掉,只保存可能收服的小精靈,

        設f[i][j]表示扔i個精靈球且皮卡丘損失j體力時所能抓到的最大精靈數,初始值全部為0,用二維費用的0/1背包進行處理,

        最后按皮卡丘損失體力從小到大回圈處理陣列元素f[n][1]~f[n][m],找到這些元素中的最大值f[n][i],此時m-i就是皮卡丘剩余體力的最大值,

        (2)源程式,

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int f[1005][505]={0};
int main()
{
    int n,m,t;
    scanf("%d%d%d",&n,&m,&t);
    int num=0;
    int w[102],v[102];
    while (t--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x>n || y>=m)       // 不可能收服的小精靈
            continue;
        w[++num]=x;
        v[num]=y;
    }
    int i,j,k;
    for (i=1;i<=num;i++)
        for (j=n;j>=w[i];j--)
            for (k=m-1;k>=v[i];k--)
                f[j][k]=max(f[j][k],f[j-w[i]][k-v[i]]+1);
    int ans=0;
    for (i=1;i<m;i++)
        if (f[n][i]>f[n][ans]) ans=i;
    printf("%d %d\n",f[n][ans],m-ans);
    return 0;
}

        上面的5個例題中,均是二維費用的0/1背包問題,實際上,若裝入背包中的物品可以裝入無數次,就是二維費用的完全背包問題了,

【例6】FATE游戲

問題描述

最近xhd正在玩一款叫做FATE的游戲,為了得到極品裝備,xhd在不停的殺怪做任務,久而久之xhd開始對殺怪產生的厭惡感,但又不得不通過殺怪來升完這最后一級,現在的問題是,xhd升掉最后一級還需n的經驗值,xhd還留有m的忍耐度,每殺一個怪xhd會得到相應的經驗,并減掉相應的忍耐度,當忍耐度降到0或者0以下時,xhd就不會玩這游戲,xhd還說了他最多只殺s只怪,請問他能升掉這最后一級嗎?

輸入

輸入資料有多組,對于每組資料第一行輸入n,m,k,s(0 < n,m,k,s < 100)四個正整數,分別表示還需的經驗值,保留的忍耐度,怪的種數和最多的殺怪數,接下來輸入k行資料,每行資料輸入兩個正整數a,b(0 < a,b < 20);分別表示殺掉一只這種怪xhd會得到的經驗值和會減掉的忍耐度,(每種怪都有無數個)

輸出

輸出升完這級還能保留的最大忍耐度,如果無法升完這級輸出-1,

輸入樣例

10 10 1 10

1 1

10 10 1 9

1 1

9 10 2 10

1 1

2 2

輸出樣例

0

-1

1

         (1)編程思路,

        由于每種怪都有無數個,而升級需要n經驗值,只殺掉s只怪,二維費用的完全背包問題,

        設f[i][j]表示減掉忍耐度i且殺掉j只怪可得到的最大經驗值,

        采用二維費用完全背包處理后,若f[m][s]>=n,則可以升級,對陣列f按第1維下標(忍耐度)從小到大搜索,若某個f[i][j]>=n,則i值就是可升級時減掉的最小忍耐度,m-i就是還能保留的最大忍耐度;若f[m][s]<n,則無法升級,

        (2)源程式,

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int f[105][105];
int main()
{
    int n,m,k,s;
    while (scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF)
    {
        memset(f,0,sizeof(f));
        int i,j,p;
        for (i=1;i<=k;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            for (j=b;j<=m;j++)       // 忍耐度
            {
                for (p=1;p<=s;p++)   // 個數限制
                {
                    f[j][p]=max(f[j][p],f[j-b][p-1]+a);
                }
            }
        }
        if (f[m][s]>=n)
        {
            for (i=1;i<=m;i++)
            {
                for (j=1;j<=s;j++)
                    if (f[i][j]>=n)
                        break;
                if (j<=s)
                    break;
            }
            printf("%d\n",m-i);
        }
        else
            printf("-1\n");
    }
    return 0;
}

        將上面的源程式提交給HDU OJ題庫HDU 2159 FATE(http://acm.hdu.edu.cn/showproblem.php?pid=2159),測評結果為Accepted

         除了上面介紹的二維費用外,有些問題可能涉及更多的費用,比如,有三個方面的費用,

【例7】買年貨

問題描述

春節將至,小明要去超市購置年貨,于是小明去了自己經常去的都尚超市,

剛到超市,小明就發現超市門口貼了一張通知,內容如下:

值此新春佳節來臨之際,為了回饋廣大顧客的支持和厚愛,特舉行春節大酬賓、優惠大放送活動,凡是都尚會員都可用會員積分兌換商品,凡是都尚會員都可免費拿k件商品,凡是購物顧客均有好禮相送,滿100元送bla bla bla bla,滿200元送bla bla bla bla bla...blablabla....

還沒看完通知,小明就高興的要死,因為他就是都尚的會員啊,迫不及待的小明在超市逛了一圈發現超市里有n件他想要的商品,小明順便對這n件商品打了分,表示商品的實際價值,小明發現身上帶了v1的人民幣,會員卡里面有v2的積分,他想知道他最多能買多大價值的商品,

由于小明想要的商品實在太多了,他算了半天頭都疼了也沒算出來,所以請你這位聰明的程式員來幫幫他吧,

輸入

輸入包含多組測驗用例,

每組資料的第一行是四個整數n,v1,v2,k;

然后是n行,每行三個整數a,b,val,分別表示每個商品的價錢,兌換所需積分,實際價值,

[Technical Specification]

1 <= n <= 100

0 <= v1, v2 <= 100

0 <= k <= 5

0 <= a, b, val <= 100

 

Ps. 只要錢或者積分滿足購買一件商品的要求,那么就可以買下這件商品,

輸出

對于每組資料,輸出能買的最大價值,

輸入樣例

5 1 6 1

4 3 3

0 3 2

2 3 3

3 3 2

1 0 2

4 2 5 0

0 1 0

4 4 1

3 3 4

3 4 4

輸出樣例

12

4

         (1)編程思路,

        每件商品可以用3種方式獲得,用錢買、用積分兌換或者用免費拿的次數免費拿,這樣涉及3個方面的費用,設f[i][j][k]表示用i元錢買,用j個積分換,免費拿k件可獲得的最大價值,就是一個3維費用的背包問題了,可用4重回圈進行處理,

         (2)源程式,

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int f[105][105][6]; // f[i][j][k]表示用i元錢買,用j個積分換,免費拿k件可獲得的最大價值
int main()
{
    int a[105],b[105],v[105];
    int n,v1,v2,k;
    while (scanf("%d%d%d%d",&n,&v1,&v2,&k)!=EOF)
    {
        int i,x1,x2,x3;
        for (i=1;i<=n;i++)
            scanf("%d%d%d",&a[i],&b[i],&v[i]);
        memset(f, 0,sizeof(f));
        int ans = 0;
        for (i=1;i<=n;i++)
          for (x1 = v1;x1>=0;x1--)
            for (x2=v2;x2>=0;x2--)
              for (x3=k;x3>=0;x3--)
              {
                    int tmp = 0;
                    if (x1 >=a[i])   // 有錢,用錢買
                        tmp = max(tmp,f[x1-a[i]][x2][x3]+v[i]);
                    if (x2 >=b[i])   // 有積分,用積分兌換
                        tmp=max(tmp,f[x1][x2-b[i]][x3] + v[i]);
                    if (x3>0)        // 可以免費拿,不拿白不拿
                        tmp=max(tmp,f[x1][x2][x3-1]+v[i]);
                    f[x1][x2][x3]=max(f[x1][x2][x3],tmp);
              }
        printf("%d\n",f[v1][v2][k]);
    }
    return 0;
}

        將上面的源程式提交給HDU OJ題庫HDU 4501小明系列故事——買年貨(http://acm.hdu.edu.cn/showproblem.php?pid=4501),測評結果為Accepted, 

練習題

1.P1507 NASA的食物計劃(https://www.luogu.com.cn/problem/P1507

#include <stdio.h>
int main()
{
    int v,m;
    scanf("%d%d",&v,&m);
    int n;
    scanf("%d",&n);
    int a[51],b[51],c[51];
    int f[401][401]={0};
    int i,j,k;
    for (i=1;i<=n;i++)
       scanf("%d%d%d",&a[i],&b[i],&c[i]);
    for (i=1;i<=n;i++)
    {
        for(j=v;j>=a[i];j--)
            for (k=m;k>=b[i];k--)
            {
               if (f[j][k]<f[j-a[i]][k-b[i]]+c[i])
                       f[j][k]=f[j-a[i]][k-b[i]]+c[i];
            }
    }
    printf("%d\n",f[v][m]);
    return 0;
}
View Code

2.P1759 通天之潛水(https://www.luogu.com.cn/problem/P1759)

#include <stdio.h>
#include <string.h>
struct Node
{
    int sum;        // 停留的總時間
    int ans[101];    // 保存選中的數,其中a[0]是選中的數的個數
};
struct Node f[201][201];
int main()
{
    int m,v,n;
    scanf("%d%d%d",&m,&v,&n);
    int a[101],b[101],c[101];
    int i,j,k,l;
    for (i=1;i<=n;i++)
       scanf("%d%d%d",&a[i],&b[i],&c[i]);
    memset(f,0,sizeof(f));
    for (i=1;i<=n;i++)
       for (j=m;j>=a[i];j--)
          for (k=v;k>=b[i];k--)
          {
              if (f[j-a[i]][k-b[i]].sum+c[i]>f[j][k].sum)
              {
                  f[j][k].sum=f[j-a[i]][k-b[i]].sum+c[i];
                  for (l=1;l<=f[j][k].ans[0];l++)
                      f[j][k].ans[l]=0;
                  f[j][k].ans[0]=f[j-a[i]][k-b[i]].ans[0]+1;
                  for (l=1;l<=f[j-a[i]][k-b[i]].ans[0];l++)
                      f[j][k].ans[l]=f[j-a[i]][k-b[i]].ans[l];
                  f[j][k].ans[f[j][k].ans[0]]=i;   // 選中i
              }
          }
    printf("%d\n",f[m][v].sum);
    for (i=1;i<=f[m][v].ans[0];i++)
        printf("%d ",f[m][v].ans[i]);
    printf("\n");
    return 0;
}
View Code

3.POJ2576 Tug of War(http://poj.org/problem?id=2576

#include <stdio.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int abs(int a)
{
    return a>0?a:-a;
}
int f[101][45001]={0};
int main()
{
    int n;
    scanf("%d",&n);
    int w[101];
    int total=0;
    int i,j,k;
    for (i= 1;i<=n; i++)
    {
        scanf("%d",&w[i]);
        total += w[i];
    }
    f[0][0] = 1;
    for (i = 1; i <= n; i ++)
       for (j = total; j >= w[i]; j --)
          for (k = 1; k <= n/2 ; k ++)
             if (f[k - 1][j - w[i]] == 1)
                 f[k][j] = 1;
    int ans = 1000000;
    int index = -1;
    for (i = total; i >= 0; i --)
       if (f[n / 2][i] == 1 && abs(i * 2 - total) < ans)
       {
          ans = abs(i * 2 - total);
          index = i;
       }
    if (index <= total / 2)
       printf("%d %d\n",index,total - index);
    else
       printf("%d %d\n",total - index,index);
    return 0;
}
View Code

4.HDU 3127 WHUgirls(http://acm.hdu.edu.cn/showproblem.php?pid=3127)

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int f[1005][1005];
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        int n,X,Y;
        scanf("%d%d%d",&n,&X,&Y);
        memset(f,0,sizeof(f));
        int x[20],y[20],value[20];
        int i,j,k;
        for (i=1; i<=n; i++)
            scanf("%d%d%d",&x[i],&y[i],&value[i]);
        for (i=0; i<=X; i++)
            for (j=0; j<=Y; j++)
                for (k=1; k<=n; k++)
                {
                    if (i>=x[k] && j>=y[k]) // 第一種情況
                        f[i][j]=max(f[i][j],max(f[x[k]][j-y[k]]+f[i-x[k]][j],f[i-x[k]][y[k]]+f[i][j-y[k]])+value[k]);
                    if (i>=y[k]&& j>=x[k])  // 第二種情況
                        f[i][j] = max(f[i][j],max(f[i][j-x[k]]+f[i-y[k]][x[k]],f[i-y[k]][j]+f[y[k]][j-x[k]])+value[k]);
                }
        printf("%d\n",f[X][Y]);
    }
    return 0;
}
View Code

5.HDU 3496 Watch The Movie(http://acm.hdu.edu.cn/showproblem.php?pid=3496

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int f[105][1005];     // f[i][j]表示買下i張影碟用j時間看完獲得的最大值
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        memset(f,-1,sizeof(f));
        int n, m, l;
        scanf("%d%d%d",&n,&m,&l);
        int i,j,k;
        for (i=0; i<=l; i++)
            f[0][i] = 0;
        for (i=1; i<=n; i++)
        {
            int w,v;
            scanf("%d%d",&w,&v);
            for (j=m; j>=1; j--)
            {
                for (k=l; k>=w; k--)
                {
                    if (f[j-1][k-w]!=-1)
                    {
                        f[j][k] = max(f[j][k], f[j-1][k-w] + v);
                    }
                }
            }
        }
        printf("%d\n",(f[m][l]==-1?0:f[m][l]));
    }
    return 0;
}
View Code

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/456962.html

標籤:C

上一篇:職工管理系統(代碼回顧1)

下一篇:UImage – 色彩直方圖 GPUImageHistogramGenerator

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more