主頁 > 後端開發 > 貪心法(二):貪心法的應用例題

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

2021-11-06 06:07:11 後端開發

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

【例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 參考源程式

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

標籤:C

上一篇:大一C語言學習筆記(11)---編程篇--寫一個程式,可以獲取從鍵盤上輸入的的三個數,并能夠判斷是否可以以這三個數字作為邊長來構成一個三角形,如果可以的話,輸出此三角形的周長及面積,要求 0 bug;

下一篇:Spring Cloud Gateway實戰之一:初探

標籤雲
其他(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