貪心法(二):貪心法的應用例題


        下面我們通過解決洛谷題庫中的幾道應用貪心法思想編寫程序的例題,進一步體會貪心法的應用。

【例1】紀念品分組。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/P1094)。

題目描述

元旦快到了,校學生會讓樂樂負責新年晚會的紀念品發放工作。為使得參加晚會的同學所獲得的紀念品價值相對均衡,他要把購來的紀念品根據價格進行分組,但每組最多只能包括兩件紀念品,並且每組紀念品的價格之和不能超過一個給定的整數。為了保證在盡量短的時間內發完所有紀念品,樂樂希望分組的數目最少。

你的任務是寫一個程序,找出所有分組方案中分組數最少的一種,輸出最少的分組數目。

輸入格式

共3行:

第一行包括一個整數 w,為每組紀念品價格之和的上上限。

第二行為一個整數 n,表示購來的紀念品的總件數。

第三行為n個正整數,每個正整數 Pi表示所對應紀念品的價格。

輸出格式

一個整數,即最少的分組數目。

輸入樣例

100

9

90 20 20 30 50 60 70 80 90

輸出樣例

6

       (1)編程思路。

        將紀念品按價格從小到大排好序。由於分組時每組最多只能有兩個紀念品,因此基於貪心法分組時,總是將當前價值最大和價值最小的紀念品進行組合,若總價值沒有超過給定的整數,則將它們分為一組;若總價值超過了給定的整數,則將價格大的紀念品單獨作為一組,如此循環直至所有紀念品分組完畢,即可求出最少的分組數目。

       (2)源程序。

#include <stdio.h>

#include <algorithm>

using namespace std;

int main()

{

   int g;

   scanf("%d",&g);

   int n;

   scanf("%d",&n);

   int p[30001];

   int i,j,tmp;

   for (i=0;i<n;i++)

   {

      scanf("%d",&p[i]);

   }

   sort(p,p+n);      // 紀念品價格從小到大排列

   int ans=0;

   i=0;  j=n-1;

   while (i<j)

   {

       if (p[i]+p[j]>g) j--;

       else

       {

           i++; j--;

       }

       ans++;

   }

   if (i==j) ans++;

   printf("%d\n",ans);

   return 0;

}

 【例2】排隊接水。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/P1223)。

題目描述

有n個人在一個水龍頭前排隊接水,假如每個人接水的時間為Ti ,請編程找出這n個人排隊的一種順序,使得n個人的平均等待時間最小。

輸入格式

第一行為一個整數 n。

第二行n 個整數,第i 個整數 Ti,表示第i個人的接水時間Ti 。

輸出格式

輸出文件有兩行,第一行為一種平均時間最短的排隊順序;第二行為這種排列方案下的平均等待時間(輸出結果精確到小數點后兩位)。

輸入樣例

10

56 12 1 99 1000 234 33 55 99 812

輸出樣例

3 2 7 8 1 4 9 6 10 5

291.90

      (1)編程思路。

        設有n個人打水,每個人的接水時間分別為T1,T2,...,Tn

​        由於對於每一個人,在場剩余每個人都要等待一次他的接水,則接水等待時間總和為T1*(n-1)+T2*(n-2)+...+Tn-1*1+Tn*0

        要讓接水總等待時間最小,就要讓T1<T2<...<Tn

​        因此本題的貪心策略是:要讓平均等待時間最小,就要讓接水時間短的人往前排先接水。將數組按照接水時間從小到大排列。求平均等待時間時,遍歷整個數組,對依次接水的每個人,將其他人在這個人接水時等待的總時間累加到sum上,最后sum除以n。

      (2)源程序。

#include <stdio.h>

int main()

{

   int n;

   scanf("%d",&n);

   int t[1001],id[1001];

   int i,j,tmp;

   for (i=0;i<n;i++)

   {

      scanf("%d",&t[i]);

      id[i]=i+1;

   }

   for (i=0;i<n-1;i++)      // 按接水時間從小到大排列

     for (j=0;j<n-1-i;j++)

     {

         if (t[j]>t[j+1])

         {

             tmp=t[j];

             t[j]=t[j+1];

             t[j+1]=tmp;

             tmp=id[j];

             id[j]=id[j+1];

             id[j+1]=tmp;

         }

     }

   for (i=0;i<n;i++)

      printf("%d ",id[i]);

   printf("\n");

   double sum=0;

   for (i=0;i<n-1;i++)

   {

       sum+=t[i]*(n-1-i);

   }

   printf("%.2f\n",sum/n);

   return 0;

}

【例3】智力大沖浪。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P1230)。

題目描述

小偉報名參加中央電視台的智力大沖浪節目。本次挑戰賽吸引了眾多參賽者,主持人為了表彰大家的勇氣,先獎勵每個參賽者m元。先不要太高興!因為這些錢還不一定都是你的?!接下來主持人宣布了比賽規則:

首先,比賽時間分為n個時段(n≤500),它又給出了很多小游戲,每個小游戲都必須在規定期限ti前完成(1≤ti≤n)。如果一個游戲沒能在規定期限前完成,則要從獎勵費m元中扣去一部分錢wi,wi為自然數,不同的游戲扣去的錢是不一樣的。當然,每個游戲本身都很簡單,保證每個參賽者都能在一個時段內完成,而且都必須從整時段開始。主持人只是想考考每個參賽者如何安排組織自己做游戲的順序。作為參賽者,小偉很想贏得冠軍,當然更想贏取最多的錢!注意:比賽絕對不會讓參賽者賠錢!

輸入格式

第1行為m,表示一開始獎勵給每位參賽者的錢;

第2行為n,表示有n個小游戲;

第3行有n個數,分別表示游戲1到n的規定完成期限;

第4行有n個數,分別表示游戲1到n不能在規定期限前完成的扣款數。

輸出格式

僅1行。表示小偉能贏取最多的錢。

輸入樣例

10000

7

4 2 4 3 1 4 6

70 60 50 40 30 20 10

輸出樣例

9950

        (1)編程思路。

        本題用貪心算法求解。因為不同的小游戲不能准時完成時具有不同的扣款數,因此貪心策略是讓扣款數額大的盡量在規定的期限內完成,這樣可先把這些游戲按照扣款的數額從大到小進行排列。然后按排序好的游戲任務進行安排,即先安排扣款數大的游戲。

        每個游戲安排玩的時間段時,若其完成期限是k,就將它安排在小於等於k的最靠后的空閑時間段。一旦出現一個不可能在規定期限內完成的游戲,則把其安排到最后的一個空時間段,因為不能完成的游戲在任意一個時間段中扣款數額都是一樣的,這樣得到的結果必然是最優的。

       (2)源程序。

#include <stdio.h>

struct node

{

    int w,t;

};

int main()

{

    int m,n;

    scanf("%d%d",&m,&n);

    struct node a[501],temp;

    int i,j,k;

    for (i=0;i<n;i++)

        scanf("%d",&a[i].t);

    for (i=0;i<n;i++)

        scanf("%d",&a[i].w);

    for (i=0;i<n-1;i++)

       for (j=0;j<n-1-i;j++)

          if (a[j].w<a[j+1].w)

          {

             temp=a[j];  a[j]=a[j+1];  a[j+1]=temp;

          }

    int b[501]={0};            // b[i]=1表示時段i已被某游戲占用

    int ans=m;

    for (i=0;i<n;i++)

    {

                   for (j=a[i].t;j>=1;j--)      //  安排在小於等於k的最靠后的空閑時間段

                   {

                            if(b[j]==0)

                            {

                                     b[j]=1;

                                     break;

                            }

                   }

                   if (j<1)                 // 沒法完成,罰款吧

                   {

                            for (k=n;k>=1;k--)    // 安排到最后的一個空時間段

                            {

                                     if (b[k]==0)

                                     {

                                               b[k]=1;

                                               break;

                                     }

                            }

                            ans-=a[i].w;

                   }

         }

    printf("%d\n",ans);

       return 0;

}

 【例4】種樹。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/P1250)。

題目描述

一條街的一邊有幾座房子,因為環保原因居民想要在路邊種些樹。

路邊的地區被分割成塊,並被編號成 1,2,…,n。每個部分為一個單位尺寸大小並最多可種一棵樹。

每個居民都想在門前種些樹,並指定了三個號碼 b,e,t。這三個數表示該居民想在地區b 和 e 之間(包括 b 和 e)種至少 t 棵樹。

居民們想種樹的各自區域可以交叉。你的任務是求出能滿足所有要求的最少的樹的數量。

輸入格式

輸入的第一行是一個整數,代表區域的個數 n(1≤n≤3×104)。

輸入的第二行是一個整數,代表房子個數 h(1≤h≤5×103)。

第 3 到第 (h+2) 行,每行三個整數,第 (i+2) 行的整數依次為 bi、ei、 ti,代表第 i 個居民想在bi 和 ei 之間種至少 ti 棵樹。

輸出格式

輸出一行一個整數,代表最少的樹木個數。

輸入樣例

9

4

1 4 2

4 6 2

8 9 2

3 5 2

輸出樣例

5

        (1)編程思路。

        本題采用貪心法求解。

        由於居民想種的樹的各自區域可以相交,為求出能夠滿足所有居民的要求所需要種樹的最少數量,就需要盡量在相交的部分種樹,這樣可以使種樹的數量最少。由於每位居民與上一位居民的相交處位於上一位居民的尾部,因此可以考慮從尾部開始種樹。

        具體的貪心策略為:先按照每戶居民的結束位置從小到大排列,如果結束位置相等,則按照開始位置從大到小排列。然后用一個數組記錄各位置點有沒有種樹。種樹時,對排序好的每位居民的要求,從后往前種,即盡量在每個居民要求的交集處種樹,這樣該樹可以為多個居民需求共用,最后種的樹也將是最少的。

        (2)源程序。

#include <stdio.h>

struct node

{

    int b,e,t;

};

int main()

{

    int n,h;

    scanf("%d%d",&n,&h);

    struct node a[5001],temp;

    int i,j;

    for (i=0;i<h;i++)

        scanf("%d%d%d",&a[i].b,&a[i].e,&a[i].t);

    for (i=0;i<h-1;i++)

       for (j=0;j<h-1-i;j++)

          if (a[j].e>a[j+1].e || (a[j].e==a[j+1].e && a[j].b<a[j+1].b))

          {

             temp=a[j];  a[j]=a[j+1];  a[j+1]=temp;

          }

    int b[30001]={0};       // b[i]=1表示位置i已種樹

    int ans=0;

    for (i=0;i<h;i++)

    {

        int sum=0;

        for (j=a[i].b;j<=a[i].e;j++)

            sum+=b[j];   // 累加在這段區間上已經種的樹的數目

        for (j=a[i].e;j>=a[i].b && sum<a[i].t;j--)

        {

            if (b[j]!=1)

            {

                b[j]=1;

                sum++;

                ans++;

            }

        }

    }

    printf("%d\n",ans);

       return 0;

}

        注:這段代碼提交給P1986 元旦晚會(https://www.luogu.com.cn/problem/ P1986)同樣可以Accepted。

【例5】County Fair Events S。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P6244)。

題目描述

FJ 參加活動。

他想參加盡可能多的 N 個活動,參加完某個之后可以立刻參加下一個。

給定 FJ 可參加的活動列表、其開始時間 T 和持續時間 L ,求 FJ 可以參加的最大活動數。

FJ 每個活動都不會提早離開。

輸入格式

第一行有一個整數 N(1≤N≤104)。

第二到 N+1 行:每行包含兩個用空格分隔的整數 T 和 L (1≤T,L≤105),意義如上述。

輸出格式

輸出僅一行,FJ 最多能參加幾個活動。

輸入樣例

7

1 6

8 6

14 5

19 2

1 8

18 3

10 6

輸出樣例

4

        (1)編程思路。

        貪心策略為:在可選的活動中,每次選取結束時間最早的活動參加。這樣之后可能選擇參加的活動就更多些。

      (2)源程序。

#include <stdio.h>

struct Event

{

    int begin,end;

};

int main()

{

    int n;

    scanf("%d",&n);

    struct Event a[10001],tmp;

    int i,j;

    for (i=0;i<n;i++)

    {

        int t,l;

        scanf("%d%d",&t,&l);

        a[i].begin=t;

        a[i].end=t+l;

    }

    for (i=0;i<n-1;i++)    // 將各活動按結束時間從早到晚排列

      for (j=0;j<n-1-i;j++)

      {

          if (a[j].end>a[j+1].end)

          {

               tmp=a[j];  a[j]=a[j+1]; a[j+1]=tmp;

          }

      }

    int cnt=1;

    int finish=a[0].end;

    for (i=1;i<n;i++)

    {

        if (a[i].begin>=finish)

        {

            cnt++;

            finish=a[i].end;

        }

    }

    printf("%d\n",cnt);

    return 0;

}

 【例6】泥濘路。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P1589)。

題目描述

暴雨過后,FJ的農場到鎮上的公路上有一些泥濘路,他有若干塊長度為L的木板可以鋪在這些泥濘路上,問他至少需要多少塊木板,才能把所有的泥濘路覆蓋住。

輸入格式

第一行為正整數n(≤10000)和L(≤10000),分別表示有多少段泥濘路和木板的長度;接下來n行,每一行兩個整數s和e(s≤e≤10^9),表示每一段泥濘路的起點和終點。

輸出格式

僅一個正整數,表示木板數。

輸入樣例

3 3

1 6

13 17

8 12

輸出樣例

5

        (1)編程思路。

        將每段泥濘路按起點從小到大排列。定義變量begin表示鋪木板的人行走到的位置,初始值為0。

        遍歷排序好的泥濘路數組,對於每段泥濘路,若begin<s[i],表示鋪木板的人所在位置與泥濘路之間不存在泥濘,無需鋪木板,直接走到這段泥濘路的起點,即begin=s[i],之后開始鋪木板,每鋪一塊木板,鋪木板人向前走L,即begin=begin+L並計數所鋪木板塊數,直到鋪木板人的位置到達或超過了這段泥濘路的終點(begin≥e[i])。

       (2)源程序。

#include <stdio.h>

int main()

{

   int n,l;

   scanf("%d%d",&n,&l);

   int s[10001],e[10001];

   int i,j,t;

   for (i=1;i<=n;i++)

       scanf("%d%d",&s[i],&e[i]);

   for (i=1;i<n;i++)

     for (j=1;j<=n-i;j++)

        if (s[j]>s[j+1])

        {

           t=s[j];  s[j]=s[j+1];  s[j+1]=t;

           t=e[j];  e[j]=e[j+1];  e[j+1]=t;

        }

   int ans=0;

   int begin=0;

   for (i=1;i<=n;i++)

   {

       if (begin<s[i]) begin=s[i];

       while (begin<e[i])

       {

           ans++;

           begin+=l;

       }

   }

   printf("%d\n",ans);

   return 0;

}

 【例7】營養膳食。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P2095)。

題目描述

Mr.L 正在完成自己的增肥計划。

為了增肥,Mr.L 希望吃到更多的脂肪。然而也不能只吃高脂肪食品,那樣的話就會導致缺少其他營養。

Mr.L 通過研究發現:真正的營養膳食規定某類食品不宜一次性吃超過若干份。比如就一頓飯來說,肉類不宜吃超過 11 份,魚類不宜吃超過 11 份,蛋類不宜吃超過 11 份,蔬菜類不宜吃超過 22 份。

Mr.L 想要在營養膳食的情況下吃到更多的脂肪,當然 Mr.L 的食量也是有限的。

輸入格式

第一行包含三個正整數 n,m和 k。表示 Mr.L 每頓飯最多可以吃 m 份食品,同時有 n 種食品供 Mr.L 選擇,而這 n 種食品分為 k 類。

第二行包含 k 個不超過 10的正整數,表示可以吃 1 到 k 類食品的最大份數。

接下來 n 行每行包括 2 個正整數,分別表示該食品的脂肪指數 ai和所屬的類別 bi。

輸出格式

包括一個數字即 Mr.L 可以吃到的最大脂肪指數和。

輸入樣例

6 6 3

3 3 2

15 1

15 2

10 2

15 2

10 2

5 3

輸出樣例

60

       (1)編程思路。

        貪心策略是優先吃脂肪指數高的食品。因此將所有食品按脂肪指數從大到小排列即可。

       (2)源程序。

#include <stdio.h>

struct Food

{

         int a,b;

};

int main()

{

         int n,m,k;

         scanf("%d%d%d",&n,&m,&k);

         int i,j,b[101];

         for (i=1;i<=k;i++)

                   scanf("%d",&b[i]);

         struct Food f[201],t;

         for (i=1;i<=n;i++)

                   scanf("%d%d",&f[i].a,&f[i].b);

         for (i=1;i<n;i++)  // 食物按脂肪含量從大到小排列

           for (j=1;j<=n-i;j++)

              if (f[j].a<f[j+1].a)

             {

                t=f[j]; f[j]=f[j+1]; f[j+1]=t;

             }

         int ans=0;

         for (i=1;i<=n;i++)

         {

                   if (b[f[i].b]>0 && m>0)  // 還沒超過這一類和總共規定

                   {

                            b[f[i].b]--;

                            m--;

                            ans+=f[i].a;

        }

         }

         printf("%d",ans);

         return 0;

}

 【例8】合並果子。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P1090)。

題目描述

在一個果園里,多多已經將所有的果子打了下來,而且按果子的不同種類分成了不同的堆。多多決定把所有的果子合成一堆。

每一次合並,多多可以把兩堆果子合並到一起,消耗的體力等於兩堆果子的重量之和。可以看出,所有的果子經過 n-1次合並之后, 就只剩下一堆了。多多在合並果子時總共消耗的體力等於每次合並所耗體力之和。

因為還要花大力氣把這些果子搬回家,所以多多在合並果子時要盡可能地節省體力。假定每個果子重量都為 1 ,並且已知果子的種類數和每種果子的數目,你的任務是設計出合並的次序方案,使多多耗費的體力最少,並輸出這個最小的體力耗費值。

例如有 3 種果子,數目依次為 1 , 2 , 9 。可以先將 1 、 2 堆合並,新堆數目為 3 ,耗費體力為 3 。接着,將新堆與原先的第三堆合並,又得到新的堆,數目為 12,耗費體力為 12。所以多多總共耗費體力 =3+12=15。可以證明 15 為最小的體力耗費值。

輸入格式

共兩行。

第一行是一個整數 n (1≤n≤10000) ,表示果子的種類數。

第二行包含 n 個整數,用空格分隔,第 i 個整數 ai (1≤ai≤20000) 是第i 種果子的數目。

輸出格式

一個整數,也就是最小的體力耗費值。輸入數據保證這個值小於231

輸入樣例

3

1 2 9

輸出樣例

15

      (1)編程思路。

        貪心策略為:每次合並當前各果子堆中果子數最少的兩堆果子,直到所有果子合並為一堆。

      (2)源程序。

#include <stdio.h>

int main()

{

   int n;

   scanf("%d",&n);

   int a[10001];

   int i,j,t;

   for (i=0;i<n;i++)

       scanf("%d",&a[i]);

   for (i=0;i<n-1;i++)

     for (j=0;j<n-1-i;j++)

     {

         if (a[j]>a[j+1])

         {

             t=a[j];

             a[j]=a[j+1];

             a[j+1]=t;

         }

     }

   int ans=0;

   for (i=0;i<n-1;i++)

   {

       t=a[i]+a[i+1];

       ans+=t;

       for (j=i+1;j<n-1;j++)

          if (a[j+1]<t) a[j]=a[j+1];

          else break;

       a[j]=t;

   }

   printf("%d\n",ans);

   return 0;

}

 【例9】運輸。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P2094)

題目描述

現在已知 N 件商品,和搬運它們其中每一件的費用。現在搬家公司老板 Mr.sb 決定讓我們每次任意選取 2 件商品。然后這 2 件商品只算一件商品的費用。但是這個商品的搬運費用是將選出的 2 個商品的費用之和除以 $k 的運算結果。如此反復。直到只收一件商品的錢。這個就是商店要付的費用。掌櫃的想盡可能的少付錢,以便將更多的錢捐給希望工程。所以請你幫他計算一下最少只用付多少錢。

輸入格式

第一行兩個整數 n,k。

第二行 n 個整數w1 ,w2,…,wn,表示每一件物品搬運費。

輸出格式

一行一個整數表示最少付多少錢。

輸入樣例

5 2

1 2 3 4 5

輸出樣例

1

        (1)編程思路。

        貪心策略為:每次選取當前未組合商品中搬運費最多的兩件商品進行組合計價,使得搬運費高的商品盡可能多的被除以k。

        (2)源程序。

#include <stdio.h>

int main()

{

   int n,k;

   scanf("%d%d",&n,&k);

   int a[10001];

   int i,j,t;

   for (i=0;i<n;i++)

       scanf("%d",&a[i]);

   for (i=0;i<n-1;i++)

     for (j=0;j<n-1-i;j++)

     {

         if (a[j]<a[j+1])

         {

             t=a[j];

             a[j]=a[j+1];

             a[j+1]=t;

         }

     }

   for (i=0;i<n-1;i++)

   {

       t=(a[i]+a[i+1])/k;

       for (j=i+1;j<n-1;j++)

          if (a[j+1]>t) a[j]=a[j+1];

          else break;

       a[j]=t;

   }

   printf("%d\n",t);

   return 0;

}

 【例10】母艦。

        本題選自洛谷題庫(https://www.luogu.com.cn/problem/ P2813)。

題目描述

在小A的星際大戰游戲中,一艘強力的母艦往往決定了一場戰爭的勝負。一艘母艦的攻擊力是普通的MA(Mobile Armor)無法比較的。

對於一艘母艦而言,它是由若干個攻擊系統和若干個防御系統組成的。兩艘母艦對決時,一艘母艦會選擇用不同的攻擊系統去攻擊對面母艦的防御系統。當這個攻擊系統的攻擊力大於防御系統的防御力時,那個防御系統會被破壞掉。當一艘母艦的防御系統全部被破壞掉之后,所有的攻擊都會攻擊到敵方母艦本身上去造成傷害。

這樣說,一艘母艦對對面的傷害在一定程度上是取決於選擇的攻擊對象的。

在瞬息萬變的戰場中,選擇一個最優的攻擊對象是非常重要的。所以需要寫出一個戰斗系統出來,判斷出你的母艦最多能對對手造成多少傷害並加以實現。

輸入格式

輸入第一行兩個整數M和N,表示對方母艦的防御系統數量和你的母艦的攻擊系統數量。

接着M行每行一個整數每一個表示對方防御系統的防御力是多少。

接着N行每行一個整數每一個表示己方攻擊系統的攻擊力是多少。

輸出格式

輸出僅有一行,表示可以造成的最大傷害。

輸入樣例

3 5

1000

2000

1200

2100

2000

1200

1000

1000

輸出樣例

2000

       (1)編程思路。

       本題的貪心策略為:在能夠打破敵方的防御系統的我方攻擊系統中,用盡量小的攻擊系統來打敵方的防御系統,這樣好留下大的攻擊系統來打母艦以造成更大的傷害。為此,將攻擊力數組和防御力數組分別按從小到大的順序排列。

       (2)源程序。

#include <stdio.h>

#include <algorithm>

using namespace std;

int main()

{

    int defense[100001],attack[100001],i;

    int m,n;

    scanf("%d%d",&m,&n);

    for (i=0;i<m;i++)

        scanf("%d",&defense[i]);

    for (i=0;i<n;i++)

        scanf("%d",&attack[i]);

    sort(defense,defense+m);

    sort(attack,attack+n);

    int k=0;  // 敵方現有的最小的防御系統

    for(i=0;i<n;i++)

    {

       if (defense[k]==0) k++;

       else if (defense[k]<attack[i])  // 當前的攻擊系統能打破敵方現有的最小的防御系統

       {

           attack[i]=0;

           k++;

       }

    }

    if (k<m)    // 打不完防御系統就一點傷害都沒有

        printf("0\n");

    else

    {

        int ans=0;

        for (i=0;i<n;i++) ans+=attack[i];

        printf("%d\n",ans);

    }

    return 0;

}

         在理解了貪心法及其應用方法的基礎上,可以刷一下如下的洛谷OJ題目。這幾道題目均可以采用貪心法解決。

        (1)P1208 [USACO1.3]混合牛奶 Mixing Milk(https://www.luogu.com.cn/problem/ P1208)。

#include <stdio.h>
struct Milk
{
    int p,a;
};
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    struct Milk a[5001];
    int i,j;
    for (i=0;i<m;i++)
        scanf("%d%d",&a[i].p,&a[i].a);
    for (i=0;i<m-1;i++)
        for (j=0;j<m-1-i;j++)
        {
           if (a[j].p>a[j+1].p)
           {
               struct Milk temp;
               temp=a[j]; a[j]=a[j+1]; a[j+1]=temp;
           }
        }
    int ans=0;
    for (i=0;i<n;i++)
    {
        if (n>a[i].a)
        {
            ans+=a[i].p*a[i].a;
            n-=a[i].a;
        }
        else
        {
            ans+=a[i].p*n;
            break;
        }
    }
    printf("%d\n",ans);
    return 0;
}
P1208 參考源程序

        (2)P1209 [USACO1.3]修理牛棚 Barn Repair(https://www.luogu.com.cn/problem/ P1209)。

#include <stdio.h>
int main()
{
   int m,s,c;
   scanf("%d%d%d",&m,&s,&c);
   int a[201],b[201];
   int i,j,t;
   for (i=1;i<=c;i++)
       scanf("%d",&a[i]);
   if (m>=c)
   {
       printf("%d\n",c);
       return 0;
   }
   for (i=1;i<c;i++)
     for (j=1;j<=c-i;j++)
        if (a[j]>a[j+1])
        {
           t=a[j];  a[j]=a[j+1];  a[j+1]=t;
        }
   int ans = a[c] - a[1] + 1;
   for (i=1;i<c;i++)
       b[i]=a[i+1]-a[i];
   for (i=1;i<c-1;i++)
     for (j=1;j<c-i;j++)
        if (b[j]<b[j+1])
        {
           t=b[j];  b[j]=b[j+1];  b[j+1]=t;
        }
   for(int i=1;i<m;i++)
   {
       ans=ans-b[i]+1;
   }
   printf("%d\n",ans);
   return 0;
}
P1209 參考源程序

       (3)P1325 雷達安裝(https://www.luogu.com.cn/problem/ P1325)。

#include <stdio.h>
#include <math.h>
struct Position
{
    int x,y;
};
struct Range
{
    double left,right;
};
int main()
{
    int n,d;
    scanf("%d%d",&n,&d);
    int flag=0;
    int i,j;
    struct Position pos[1001];
    struct Range dis[1001];
    for (i=0;i<n;i++)
    {
        scanf("%d%d",&pos[i].x,&pos[i].y);
        if (d>=pos[i].y)
        {
            double dd=sqrt(d*d-pos[i].y*pos[i].y);
            dis[i].left=pos[i].x-dd;
            dis[i].right=pos[i].x+dd;
        }
        else
            flag=1;
    }
    if (flag)
        printf("-1\n");
    else
    {
        for (i=0;i<n-1;i++)
            for (j=0;j<n-1-i;j++)
               if (dis[j].right>dis[j+1].right)
               {
                   struct Range temp;
                   temp=dis[j]; dis[j]=dis[j+1]; dis[j+1]=temp;
               }
        int cnt=1;
        double finish=dis[0].right;
        for (i=1;i<n;i++)
        {
            if (dis[i].left>finish)
            {
               cnt++;
               finish=dis[i].right;
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}
P1325 參考源程序

      (4)P1645序列(https://www.luogu.com.cn/problem/ P1645)。

#include <stdio.h>
struct node
{
    int b,e,t;
};
int main()
{
    int n;
    scanf("%d",&n);
    struct node a[1001],temp;
    int i,j;
    for (i=0;i<n;i++)
        scanf("%d%d%d",&a[i].b,&a[i].e,&a[i].t);
    for (i=0;i<n-1;i++)
       for (j=0;j<n-1-i;j++)
          if (a[j].e>a[j+1].e || (a[j].e==a[j+1].e && a[j].b<a[j+1].b))
          {
             temp=a[j];  a[j]=a[j+1];  a[j+1]=temp;
          }
    int b[1001]={0};
    int ans=0;
    for (i=0;i<n;i++)
    {
        int sum=0;
        for (j=a[i].b;j<=a[i].e;j++)
            sum+=b[j];
        for (j=a[i].e;j>=a[i].b && sum<a[i].t;j--)
        {
            if (b[j]!=1)
            {
                b[j]=1;
                sum++;
                ans++;
            }
        }
    }
    printf("%d\n",ans);
      return 0;
}
P1645 參考源程序

      (5)P1803 凌亂的yyy / 線段覆蓋(https://www.luogu.com.cn/problem/ P1803)。

#include <stdio.h>
#include <algorithm>
using namespace std;
struct Match
{
    int begin,end;
};
struct Match a[1000001];
int cmp(struct Match a,struct Match b)
{
    return a.end<b.end;
}
int main()
{
    int n;
    scanf("%d",&n);

    int i,j;
    for (i=0;i<n;i++)
      scanf("%d%d",&a[i].begin,&a[i].end);
    sort(a,a+n,cmp);
    int cnt=1;
    int finish=a[0].end;
    for (i=1;i<n;i++)
    {
        if (a[i].begin>=finish)
        {
            cnt++;
            finish=a[i].end;
        }
    }
    printf("%d\n",cnt);
    return 0;
}
P1803 參考源程序

      (6)P1842 [USACO05NOV]奶牛玩雜技(https://www.luogu.com.cn/problem/ P1842)。

#include <stdio.h>
#include <algorithm>
using namespace std;
struct node
{
    int w,s;
};
int cmp(struct node a,struct node b)
{
    return a.w+a.s<b.w+b.s;
}
int main()
{
    int n;
    scanf("%d",&n);
    struct node cow[50001],t;
    int i,j;
    for (i=0;i<n;i++)
        scanf("%d%d",&cow[i].w,&cow[i].s);
    sort(cow,cow+n,cmp);
    int ans=-2000000000;
    int sum=0;
    for (i=0;i<n;i++)
    {
        if (sum-cow[i].s>ans) ans=sum-cow[i].s;
        sum+=cow[i].w;
    }
    printf("%d\n",ans);
    return 0;
}
P1842 參考源程序

      (7)P2242 公路維修問題(https://www.luogu.com.cn/problem/ P2242)。

#include <stdio.h>
int main()
{
   int n,m;
   scanf("%d%d",&n,&m);
   int a[15001],b[15001];
   int i,j,t;
   for (i=1;i<=n;i++)
       scanf("%d",&a[i]);
   int ans = a[n] - a[1] + 1;
   for (i=1;i<n;i++)       //計算出每兩個坑間的距離
       b[i]=a[i+1]-a[i];
   for (i=1;i<n-1;i++)
     for (j=1;j<n-1;j++)
        if (b[j]<b[j+1])
        {
           t=b[j];  b[j]=b[j+1];  b[j+1]=t;
        }
   for(int i=1;i<m;i++)
   {
       ans=ans-b[i]+1;
   }
   printf("%d\n",ans);
   return 0;
}
P2242 參考源程序

      (8)P2945 [USACO09MAR]Sand Castle S(https://www.luogu.com.cn/problem/ P2945)。

#include <stdio.h>
#include <algorithm>
using namespace std;
int main()
{
    int a[25001],b[25001],i,j;
    int n,x,y;
    scanf("%d%d%d",&n,&x,&y);
    for (i=0;i<n;i++)
        scanf("%d%d",&a[i],&b[i]);
    sort(a,a+n);
    sort(b,b+n);
    int ans=0;
    for (i=0;i<n;i++)
        if (a[i]>b[i]) ans+=(a[i]-b[i])*y;
        else ans+=(b[i]-a[i])*x;
    printf("%d\n",ans);
    return 0;
}
P2945 參考源程序

      (9)P3143 [USACO16OPEN]Diamond Collector S(https://www.luogu.com.cn/problem/ P3143)。

#include <stdio.h>
#include <algorithm>
using namespace std;
int max(int a,int b)
{
    return a>b?a:b;
}
int main(void)
{
    int n,k;
    scanf("%d%d",&n,&k);
    int a[50001];
    int i,j;
    for(i=1;i<=n;i++)
      scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int pos=1;
    int left[50001]={0},right[50001]={0};
    for(i=1;i<=n;i++)
    {
       while (a[i]-a[pos]>k) pos++;
       left[i]=max(left[i-1],i-pos+1);
    }
    pos=n;
    for(i=n;i>=1;i--)
    {
       while (a[pos]-a[i]>k) pos--;
       right[i]=max(right[i+1],pos-i+1);
    }
    int ans=0;
    for(i=1;i<n;i++)
    {
        ans=max(ans,left[i]+right[i+1]);
    }
    printf("%d\n",ans);
    return 0;
}
P3143 參考源程序

      (10)P4995 跳跳!(https://www.luogu.com.cn/problem/ P4995)。

#include <stdio.h>
int main()
{
   int n;
   scanf("%d",&n);
   int a[301];
   int i,j,t;
   for (i=0;i<n;i++)
      scanf("%d",&a[i]);
   for (i=0;i<n-1;i++)
     for (j=0;j<n-1-i;j++)
       if (a[j]<a[j+1])
       {
          t=a[j]; a[j]=a[j+1]; a[j+1]=t;
       }
   long long ans=1ll*a[0]*a[0];
   int left=1;
   int right=n-1;
   while (left<=right)
   {
       ans+=1ll*(a[left-1]-a[right])*(a[left-1]-a[right]);
       right--;
       if (left<=right)
         ans+=1ll*(a[left]-a[right+1])*(a[left]-a[right+1]);
       left++;
   }
   printf("%lld\n",ans);
   return 0;
}
P4995 參考源程序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM