C語言程序設計100例之(38):塗國旗


例38   塗國旗

題目描述

某國法律規定,只要一個由 N×M 個小方塊組成的旗幟符合如下規則,就是合法的國旗。

從最上方若干行(至少一行)的格子全部是白色的;

接下來若干行(至少一行)的格子全部是藍色的;

剩下的行(至少一行)全部是紅色的;

現有一個棋盤狀的布,分成了 N 行 M 列的格子,每個格子是白色藍色紅色之一,小 a 希望把這個布改成該國國旗,方法是在一些格子上塗顏料,蓋住之前的顏色。

小a很懶,希望塗最少的格子,使這塊布成為一個合法的國旗。

輸入格式

第一行是兩個整數 N,M。

接下來 N 行是一個矩陣,矩陣的每一個小方塊是W(白),B(藍),R(紅)中的一個。

輸出格式

一個整數,表示至少需要塗多少塊。

輸入樣例

4 5

WRWRW

BWRWB

WRWRW

RWBWR

輸出樣例

11

         (1)編程思路。

        定義數組int  w[51],b[51],r[51];數組元素w[i]、b[i]和r[i]分別表示把前i行全部塗成白色、藍色或紅色所需要塗的格子數。

        設藍色所在的行是第i行到第j行,則第1行到第i-1行是白色,第j+1行到第n行是紅色,此時需要塗的格子數為w[i-1]+b[j]-b[i-1]+r[n]-r[j]。

        對藍色所在的行i~j進行窮舉,顯然2≤i≤n-1,i≤j≤n-1。對窮舉的每種情況找出所需要塗的格子數(w[i-1]+b[j]-b[i-1]+r[n]-r[j])的最小值即可。

         (2)源程序。

#include <stdio.h>

int main()

{

    int w[51]={0},b[51]={0},r[51]={0};

    int n,m;

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

    char s[51];

    int i,j;

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

    {

        scanf("%s",s);

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

        {

            if (s[j]!='W') w[i]++;

            if (s[j]!='B') b[i]++;

            if (s[j]!='R') r[i]++;

        }

        w[i]+=w[i-1];

        b[i]+=b[i-1];

        r[i]+=r[i-1];

    }

    int ans=50*50;

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

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

        {

            int t;

            t=w[i-1]+b[j]-b[i-1]+r[n]-r[j];

           if (ans>t) ans=t;

        }

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

         return 0;

}

習題38

38-1  健康的奶牛

        本題選自洛谷題庫 (https://www.luogu.org/problem/ P1460)。

題目描述

農民 John 以擁有世界上最健康的奶牛為傲。他知道每種飼料中所包含的牛所需的最低的維他命量是多少。請你幫助農夫喂養他的牛,以保持它們的健康,使喂給牛的飼料的種數最少。

給出牛所需的最低的維他命量,輸出喂給牛需要哪些種類的飼料,且所需的飼料劑量最少。

維他命量以整數表示,每種飼料最多只能對牛使用一次,數據保證存在解。

輸入格式

第一行一個整數 v(1≤v≤25),表示需要的維他命的種類數。

第二行 v 個整數,表示牛每天需要的每種維他命的最小量。

第三行一個整數 g(1≤g≤15),表示可用來喂牛的飼料的種數。

下面 g 行,第 n 行表示編號為 n 飼料包含的各種維他命的量的多少。

輸出格式

輸出文件只有一行,包括牛必需的最小的飼料種數 p;后面有 p 個數,表示所選擇的飼料編號(按從小到大排列)。

如果有多個解,輸出飼料序號最小的(即字典序最小)。

輸入樣例

4

100 200 300 400

3

50  50  50  50

200 300 200 300

900 150 389 399

輸出樣例

2 1 3

         (1)編程思路。

        g種飼料,每種有選用和不選用兩種狀態。一共有2g種狀態,因為g最多為15,因此狀態量最多為215,可以用二進制位運算枚舉g種飼料的各種狀態組合,檢查每種狀態組合是否滿足牛所需的最低的維他命量,並進行相應的更新處理。

         例如,當g=3時,有3種飼料(設為a,b,c這3種),8種組合狀態,其中0(000)表示三種飼料均不選用,1(001)表示只選用飼料c,2(010)表示只選用飼料b,3(011)表示選用飼料b和c,4(100)表示選用飼料a,…,7(111)表示3種飼料全部選用。

        (2)源程序。

#include <stdio.h>

int main()

{

    int v,g;

    scanf("%d",&v);

    int a[26];

    int i,j,k;

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

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

    scanf("%d",&g);

    int map[16][26];

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

      for (j=0;j<v;j++)

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

    int cnt=15,num;

    for (k=1;k<(1<<g);k++)      //  枚舉所有狀態

    {

       int lowbit=k;

       int b[26];

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

           b[i]=0;

       int p=0;

       for (i=0; lowbit>0; i++,lowbit>>=1)

          if (lowbit&1)

          {

              p++;

              for (j=0;j<v;j++)

              {

                  b[j]+=map[i][j];

              }

           }

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

            if (a[i]>b[i]) break;

       if (i>=v && p<cnt)

       {

          cnt=p;

          num=k;

       }

    }

    printf("%d ",cnt);

    for (i=1; num>0;i++,num>>=1)

       if (num&1)

          printf("%d ",i);

    printf("\n");

    return 0;

}

38-2  海明碼

        本題選自洛谷題庫 (https://www.luogu.org/problem/ P1461)。

題目描述

給出 n、b、d,要求找出n個由 0、1組成的編碼,每個編碼有b位,使得兩兩編碼之間至少有 d個單位的 “Hamming距離”。

“Hamming距離”是指對於兩個編碼,它們二進制表示法中的不同二進制位的數目。看下面的兩個編碼 0x554 和 0x234(十六進制數)

0x554 = 0101 0101 0100

0x234 = 0010 0011 0100

不同位     xxx    xx

因為有五個位不同,所以“Hamming距離”是 5。

輸入格式

一行,包括 n,b,d。1≤n≤64,1≤b≤8,1≤d≤7。

輸出格式

n 個編碼(用十進制表示),要排序,十個一行。

如果有多解,你的程序要輸出這樣的解:假如把它化為 2b進制數,它的值要最小。

輸入樣例

16 7 3

輸出樣例

0 7 25 30 42 45 51 52 75 76

82 85 97 102 120 127

         (1)編程思路。

        由於二進制數位的異或運算具有一個特點:相同的數位異或為0,不同的數位異或為1。因此,兩個數的“Hamming距離”實際就是兩個數異或后,結果中二進制數位“1”的個數。

定義數組int a[256];存放滿足“Hamming距離”大於或等於d的數。初始時a[0]=0,表示0是保存的第1個數。

        用循環對1~2b-1之間的每個整數進行窮舉,將窮舉到的當前數i和a數組中已經保存的所有數據進行比較,若i分別與已保存的每個數異或的結果中“1”的個數均不小於d,則保存數據i。

      (2)源程序。

#include <stdio.h>

int bitCount(int x)

{

    int cnt=0;

    while (x!=0)

    {

        cnt++;

        x=x&(x-1);

    }

    return cnt;

}

int main(void)

{

    int n,b,d;

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

    int a[256];

    int cnt=1;

    a[0]=0;

    int i,j;

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

    {

        for (j=0;j<cnt;j++)

            if (bitCount(i^a[j])<d) break;

        if(j>=cnt)

            a[cnt++] = i;

        if (cnt == n)

            break;

    }

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

    {

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

        if ((i+1)%10==0)

            printf("\n");

    }

    return 0;

}

38-3  彩彈游戲

        本題選自洛谷題庫(https://www.luogu.org/problem/ P6200)。

題目描述

奶牛們最近從玩具商那里,買來了一套仿真版彩彈游戲設備(類似於真人 CS)。Bessie 把她們玩游戲的草坪划分成了 N×N 的矩陣(1≤N≤100),同時她算出了她的 K 個對手在草地上的位置(1≤K≤105),現在你需要幫 Bessie 算些東西。

在這個游戲中,奶牛們用一把槍向八個方向中的任意一個方向射出子彈,這八個方向分別是:正北,正南,正東,正西,東北,東南,西北,西南(東北指北偏東45∘,東南,西北,西南同理)。

Bessie 想要你算出,有多少個位置可以讓她射到所有對手。特別地,Bessie 可以和她的某一個對手站在同一格子,這時候她可以射到和她同一格子的對手。

輸入格式

第一行兩個整數 N,K。

接下來 K 行,每行兩個整數 Ri和 Ci,表示第 i 頭奶牛在第Ri行第Ci列。可能有兩個奶牛在同一位置上。

輸出格式

輸出 Bessie 可以選擇的格子數目。

輸入樣例

4 3

2 1

2 3

4 1

輸出樣例

5

        (1)編程思路。

        用二重循環對(1,1)~(N,N)這N2個位置進行窮舉,若某個位置能射到所有對手,則計數。

       (2)源程序。

#include <stdio.h>

int abs(int a)

{

    return a>=0?a:-a;

}

int main()

{

    int n,k;

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

    int i,x,y;

    int tot=0,ans=0;

    int v[101][101]={0};

    int a[10001][2];

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

    {

        scanf("%d%d",&x,&y);

        if (!v[x][y])

        {

           v[x][y]=1;

           a[tot][0]=x;

           a[tot][1]=y;

           tot++;

        }

    }

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

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

      {

          int f=1;

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

          {

             int dx=abs(x-a[i][0]);

             int dy=abs(y-a[i][1]);

             if (dx!=dy && dx!=0 && dy!=0)

             {

                 f=0;

                 break;

             }

          }

          ans+=f;

        }

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

    return 0;

}


免責聲明!

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



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