第三屆藍橋杯 c/c++真題

第三屆藍橋杯真題 c/c++

  如下題目我本身也並非全部的題目都是一次性就能作對或是有結題思路的。有些題目也是通過查證網上相關的資料或是參考了別人的代碼和解題思路才作出來的。總的來看,這份題目考了不少循環的只是,還有模擬,動態規劃的只是。c++

  其中作題過程當中,也有了一些新的體會。起初作代碼填空題的時候我沒辦法知道本身作的是對仍是錯,就跑到網上查答案,後來發現,題目已經給出了代碼,起始咱們能夠本身加上頭文件,而後把空缺的代碼加上進行調試的,這樣就能夠驗證本身補充的代碼是否正確了。算法

  此外在進行調試的時候,能夠利用重定向,將輸入輸出重定向到文件中,例如:編程

    輸入重定向:freopen("testin.txt","r",stdin)數組

    輸出重定向: freopen("testout.txt","w",stdout);安全

  重定向之後,再有大量輸入數據或者是大量輸出數據的時候就省去了輸出測試數據的時間,仍是比較方便的。可是須要注意的是,再編程答題須要提交代碼的時候必定要記得把重定向語句註釋掉或者刪掉,否者將會出錯。函數

  結果填空題,因爲只須要結果,因此咱們的算法沒必要要很優,有不少時候都是能夠用窮舉的暴力解決方案獲取答案的。測試

  如下的題目我也只是作了簡單的測試,雖然測試結果是正確的。可是也不保證答案的正確性,因此若是有錯的地方能夠幫忙加以改正。。。編碼

《1》微生物增值

問題spa

假設有兩種微生物 X 和 Y操作系統

X出生後每隔3分鐘分裂一次(數目加倍),Y出生後每隔2分鐘分裂一次(數目加倍)。

一個新出生的X,半分鐘以後吃掉1個Y,而且,今後開始,每隔1分鐘吃1個Y。

如今已知有新出生的 X=10, Y=89,求60分鐘後Y的數目。

若是X=10,Y=90 呢?

本題的要求就是寫出這兩種初始條件下,60分鐘後Y的數目。


題目的結果令你震驚嗎?這不是簡單的數字遊戲!真實的生物圈有着一樣脆弱的性質!也許由於你消滅的那隻 Y 就是最終致使 Y 種羣滅絕的最後一根稻草!

請忍住悲傷,把答案寫在「解答.txt」中,不要寫在這裏!

解析

  能夠將時間的推移以0.5分鐘爲步長,分層6個階段,每一個階段的X用素組x[7]表示,其中x[i]表示分裂後第0.5*i分鐘的x個數,週期爲6。

其中x[1]、x[3]、x[5]的X會吃掉Y;而x[6]的X會增值,增值後的X轉到狀態x[1]從新開始新一次的循環。60分鐘後,既爲120個半分鐘後,而Y每2分鐘分裂一次,既爲每4個半分鐘分裂一次。

答案

0
94371840

 參考代碼

複製代碼
#include<stdio.h>
#include<stdlib.h>
#define M 1000
int main()
{
    long long xn,yn,newx,x[7];
    int s=120,i,j;
    
    scanf("%d%d",&xn,&yn);
    for(i=0;i<7;i++)x[i]=0;
    x[1]=xn;
    for(i=1;i<=s;i++)
    {
        yn=yn-x[1]-x[3]-x[5];//X吃Y
        if(yn<=0){yn=0;break;}//y被吃完了
        newx=2*x[6];//X增值
        for(j=6;j>1;j--)x[j]=x[j-1];//X的狀態轉移
        x[1]=newx;
        if(i%4==0)yn=2*yn;//Y增值
    }
    
    printf("%lld\n",yn);
    
    return 0; 
} 
複製代碼

 

《2》古堡算式

問題

福爾摩斯到某古堡探險,看到門上寫着一個奇怪的算式:

ABCDE * ? = EDCBA

他對華生說:「ABCDE應該表明不一樣的數字,問號也表明某個數字!」

華生:「我猜也是!」

因而,兩人沉默了很久,仍是沒有算出合適的結果來。

請你利用計算機的優點,找到破解的答案。

把 ABCDE 所表明的數字寫出來。

答案寫在「解答.txt」中,不要寫在這裏!

? 0-9
A 0-9
E 0-9
B 0-9
C 0-9
D 0-9
E 0-9

分析

  本題中總共有7中不一樣的符號,能夠用7重嵌套循環進行暴力求解知足等式的狀況既可。

答案

A 2
B 1
C 9
D 7
E 8
? 4

參開代碼

複製代碼
/*
總結:有時候若是容許的話,可使用窮舉法進行求解 。此外不是什麼判斷條件均可以在for(;;)循環的中間的,其中第一個空填初始條件,第二個條件
        爲跳出循環的條件,最後一個空爲迭代條件。 
*/

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int a,b,c,d,e,f,i=0;
    for(a=0;a<=9;a++)//2 
    {
        for(b=0;b<=9;b++)//1 
        {
            if(b==a)continue;
            for(c=0;c<=9;c++)//9
            {
                if(c==a||c==b)continue;
                for(d=0;d<=9;d++)//7
                {
                    if(d==a||d==b||d==c)continue;
                    for(e=0;e<=9;e++)//8
                    {
                        if(e==a||e==b||e==c||e==d)continue;
                        for(f=0;f<=9;f++)//4
                        {
                            if(f==a||f==b||f==c||f==d||f==e)continue;
                            if((a*10000+b*1000+c*100+d*10+e)*f==(e*10000+d*1000+c*100+b*10+a))
                            {
                                printf("%d  %d  %d  %d  %d %d",a,b,c,d,e,f);
          
                            }
                            
                        }
                    }
                }
            }
        }
    }
    
    return 0;
}
複製代碼

 《3》比酒量

問題

有一羣海盜(很少於20人),在船上比拼酒量。過程以下:打開一瓶酒,全部在場的人平分喝下,有幾我的倒下了。再打開一瓶酒平分,又有倒下的,再次重複...... 直到開了第4瓶酒,坐着的已經所剩無幾,海盜船長也在其中。當第4瓶酒平分喝下後,你們都倒下了。

等船長醒來,發現海盜船擱淺了。他在航海日誌中寫到:「......昨天,我正好喝了一瓶.......奉勸你們,開船不喝酒,喝酒別開船......」

請你根據這些信息,推斷開始有多少人,每一輪喝下來還剩多少人。

若是有多個可能的答案,請列出全部答案,每一個答案佔一行。

格式是:人數,人數,...

例如,有一種多是:20,5,4,2,0

答案寫在「解答.txt」中,不要寫在這裏!

分析

  此題能夠用4重嵌套循環求解,每重循環的控制變量爲喝第i瓶酒前的人數。此處解題的關鍵是:一、每次喝酒都是評分;2船長喝完第四瓶酒後才倒下,而且船長總共和了一瓶酒。

答案

12 6 4 2 0
15 10 3 2 0
18 9 3 2 0
20 5 4 2 0

參考代碼

複製代碼
#include<stdio.h>

int main()
{
    //freopen("result.txt","w+",stdout);
    
    int p,i,j,k;
    
    for(p=4;p<=20;p++)//第一瓶酒前人數
    {
        for(i=1;i<p;i++)//第二瓶酒前人數
        {
            for(j=1;j<i;j++)//第三瓶酒前人數
            {
                for(k=1;k<j;k++)//第四瓶酒前人數
                {
                    float num=1.0/p+1.0/i+1.0/j+1.0/k; //船長喝了一瓶酒
                    if(num==1){ 
                      printf("%d %d %d %d %d\n",p,i,j,k,0);
                    }
                }
            }
        } 
    }
   
    return 0;
} 
複製代碼

 《4》奇怪的比賽

問題

某電視臺舉辦了低碳生活大獎賽。題目的計分規則至關奇怪:

每位選手須要回答10個問題(其編號爲1到10),越後面越有難度。答對的,當前分數翻倍;答錯了則扣掉與題號相同的分數(選手必須回答問題,不回答按錯誤處理)。

每位選手都有一個起步的分數爲10分。

某獲勝選手最終得分恰好是100分,若是不讓你看比勝過程,你能推斷出他(她)哪一個題目答對了,哪一個題目答錯了嗎?

若是把答對的記爲1,答錯的記爲0,則10個題目的回答狀況能夠用僅含有1和0的串來表示。例如:0010110011 就是可能的狀況。

你的任務是算出全部可能狀況。每一個答案佔一行。

答案寫在「解答.txt」中,不要寫在這裏!

 分析

   最簡單的思路就是,十重嵌套循環,沒一衝循環表明一套題的答題狀況。最後選出知足條件的答案輸出。可是十重循環未免有些多了,難於發現錯誤,起始有不少時候遞歸和循環都是能夠互換的。

而這一道題,每回答一道題都是獨立的,而且每一道題只有兩種狀況,答對或者答錯。void fun(int pos,int fen);遞歸函數,pos是題號,而fen是當前有的分數,則遞歸出口爲當pos==10的時候

既達到最後一道題的時候,這時能夠檢查已有的fen和當前第10道題的答題分數進行計算求和,是否獲得100分,如果則輸出結果,否在不處理,最後回溯。若pos!=10則應該分兩種狀況調用遞歸函數。

答案

0010110011
0111010000
1011010000

參看代碼

複製代碼
/*
    本題若是用10個嵌套循環的話,代碼量很是大,而且容易出錯,不易於檢查。
    若是能用遞歸實現,代碼簡介,而且容易發現錯誤。
    
    因此再作題的時候應該多考慮一下解題的方法,若是一開始就立刻扎頭進去用多重嵌套循環實現的話,有可能要花費在調試上的時間
    都比編碼的時間長。 
*/

#include<stdio.h>

int x[11];

void display()
{
    int i;
    for(i=1;i<=10;i++)
    {
        printf("%d",x[i]);
    }
    printf("\n");
}

void fun(int pos,int fen)
{
    if(pos==10)
    {
        if((fen-pos)==100)
        {
            x[pos]=0;
            display();
        }
        if((fen*2)==100)
        {
            x[pos]=1;
            display();
        }
    }
    else
    {
        x[pos]=0;
        fun(pos+1,fen-pos);
        x[pos]=1;
        fun(pos+1,fen*2);
    }
}

int main()
{
    fun(1,10);
    return 0;
} 
複製代碼

 《5》轉方陣

問題

 

對一個方陣轉置,就是把原來的行號變列號,原來的列號變行號

例如,以下的方陣:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

轉置後變爲:

1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16

但,若是是對該方陣順時針旋轉(不是轉置),倒是以下結果:

13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4

下面的代碼實現的功能就是要把一個方陣順時針旋轉。

void rotate(int* x, int rank)
{
int* y = (int*)malloc(___________________); // 填空

for(int i=0; i<rank * rank; i++)
{
y[_________________________] = x[i]; // 填空
}

for(i=0; i<rank*rank; i++)
{
x[i] = y[i];
}

free(y);
}

int main(int argc, char* argv[])
{
int x[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
int rank = 4;

rotate(&x[0][0], rank);

for(int i=0; i<rank; i++)
{
for(int j=0; j<rank; j++)
{
printf("%4d", x[i][j]);
}
printf("\n");
}

return 0;
}

 

請分析代碼邏輯,並推測劃線處的代碼。

答案寫在 「解答.txt」 文件中

注意:只寫劃線處應該填的內容,劃線先後的內容不要抄寫。

 

答案

(1)

rank*rank*sizeof(int)

rank-i/rank-1+rank*(i%rank)

或者

(2)

rank*rank*sizeof(int)

(i%rank+(i%rank+1)*(rank-1))-i/rank

 

心得

  代碼填空題,能夠將題目所給的代碼複製到編譯環境中進行調試,以進一步驗證結果的正確性。

 

《6》大數乘法

問題


對於32位字長的機器,大約超過20億,用int類型就沒法表示了,咱們能夠選擇int64類型,但不管怎樣擴展,固定的整數類型老是有表達的極限!若是對超級大整數進行精確運算呢?一個簡單的辦法是:僅僅使用現有類型,可是把大整數的運算化解爲若干小整數的運算,即所謂:「分塊法」。

如圖【1.jpg】表示了分塊乘法的原理。能夠把大數分紅多段(此處爲2段)小數,而後用小數的屢次運算組合表示一個大數。能夠根據int的承載能力規定小塊的大小,好比要把int分紅2段,則小塊可取10000爲上限值。注意,小塊在進行縱向累加後,須要進行進位校訂。

如下代碼示意了分塊乘法的原理(乘數、被乘數都分爲2段)。

void bigmul(int x, int y, int r[])
{
int base = 10000;
int x2 = x / base;
int x1 = x % base; 
int y2 = y / base;
int y1 = y % base;

int n1 = x1 * y1; 
int n2 = x1 * y2;
int n3 = x2 * y1;
int n4 = x2 * y2;

r[3] = n1 % base;
r[2] = n1 / base + n2 % base + n3 % base;
r[1] = ____________________________________________; // 填空
r[0] = n4 / base;

r[1] += _______________________; // 填空
r[2] = r[2] % base;
r[0] += r[1] / base;
r[1] = r[1] % base;
}


int main(int argc, char* argv[])
{
int x[] = {0,0,0,0};

bigmul(87654321, 12345678, x);

printf("%d%d%d%d\n", x[0],x[1],x[2],x[3]);

return 0;
}


請分析代碼邏輯,並推測劃線處的代碼。

答案寫在 「解答.txt」 文件中

注意:只寫劃線處應該填的內容,劃線先後的內容不要抄寫。

提示

  將代碼複製到編譯環境中進行調試,計算的結果能夠經過電腦附件中的計算器的計算記過進行對照以驗證正確與否。

 答案

n2/base+n3/base+n4%base
r[2]/base

《7》放棋子


今有 6 x 6 的棋盤格。其中某些格子已經預先放好了棋子。如今要再放上去一些,使得:每行每列都正好有3顆棋子。咱們但願推算出全部可能的放法。下面的代碼就實現了這個功能。

初始數組中,「1」表示放有棋子,「0」表示空白。


今有 6 x 6 的棋盤格。其中某些格子已經預先放好了棋子。如今要再放上去一些,使得:每行每列都正好有3顆棋子。咱們但願推算出全部可能的放法。下面的代碼就實現了這個功能。

初始數組中,「1」表示放有棋子,「0」表示空白。

int N = 0;

bool CheckStoneNum(int x[][6])//檢查棋盤各行各列是否知足要求
{
for(int k=0; k<6; k++)
{
int NumRow = 0;
int NumCol = 0;
for(int i=0; i<6; i++)
{
if(x[k][i]) NumRow++;
if(x[i][k]) NumCol++;
}
if(_______NumRow!=3||NumCol!=3______________) return false; // 填空
}
return true;
}

int GetRowStoneNum(int x[][6], int r)//獲取行旗子數
{
int sum = 0;
for(int i=0; i<6; i++) if(x[r][i]) sum++;
return sum;
}

int GetColStoneNum(int x[][6], int c)//獲取列旗子數
{
int sum = 0;
for(int i=0; i<6; i++) if(x[i][c]) sum++;
return sum;
}

void show(int x[][6])
{
for(int i=0; i<6; i++)
{
for(int j=0; j<6; j++) printf("%2d", x[i][j]);
printf("\n");
}
printf("\n");
}

void f(int x[][6], int r, int c);

void GoNext(int x[][6], int r, int c)
{
if(c<6)
_f(x, r, c+1)______________________; // 填空
else
f(x, r+1, 0);
}

void f(int x[][6], int r, int c)
{
if(r==6)//已經遍歷到最後一行了
{
if(CheckStoneNum(x))
{
N++;
show(x);
}
return;
}

if(_x[r][c]_____________) // 已經放有了棋子
{
GoNext(x,r,c);
return;
}

int rr = GetRowStoneNum(x,r);
int cc = GetColStoneNum(x,c);

if(cc>=3) // 本列已滿
GoNext(x,r,c); 
else if(rr>=3) // 本行已滿
f(x, r+1, 0); 
else
{
x[r][c] = 1;
GoNext(x,r,c);
x[r][c] = 0;

if(!(3-rr >= 6-c || 3-cc >= 6-r)) // 本行或本列嚴重缺子,則本格不能空着!
GoNext(x,r,c); 
}
}

int main(int argc, char* argv[])
{
int x[6][6] = {
{1,0,0,0,0,0},
{0,0,1,0,1,0},
{0,0,1,1,0,1},
{0,1,0,0,1,0},
{0,0,0,1,0,0},
{1,0,1,0,0,1}
};

f(x, 0, 0);

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

return 0;
}


請分析代碼邏輯,並推測劃線處的代碼。

答案寫在 「解答.txt」 文件中

注意:只寫劃線處應該填的內容,劃線先後的內容不要抄寫。

 答案

NumRow!=3||NumCol!=3
f(x, r, c+1)
x[r][c]

 

《8》密碼發生器

問題


在對銀行帳戶等重要權限設置密碼的時候,咱們經常遇到這樣的煩惱:若是爲了好記用生日吧,容易被破解,不安全;若是設置很差記的密碼,又擔憂本身也會忘記;若是寫在紙上,擔憂紙張被別人發現或弄丟了...

這個程序的任務就是把一串拼音字母轉換爲6位數字(密碼)。咱們可使用任何好記的拼音串(好比名字,王喜明,就寫:wangximing)做爲輸入,程序輸出6位數字。

變換的過程以下:

第一步. 把字符串6個一組摺疊起來,好比wangximing則變爲:
wangxi
ming

第二步. 把全部垂直在同一個位置的字符的ascii碼值相加,得出6個數字,如上面的例子,則得出:
228 202 220 206 120 105

第三步. 再把每一個數字「縮位」處理:就是把每一個位的數字相加,得出的數字若是不是一位數字,就再縮位,直到變成一位數字爲止。例如: 228 => 2+2+8=12 => 1+2=3

上面的數字縮位後變爲:344836, 這就是程序最終的輸出結果!

要求程序從標準輸入接收數據,在標準輸出上輸出結果。

輸入格式爲:第一行是一個整數n(<100),表示下邊有多少輸入行,接下來是n行字符串,就是等待變換的字符串。
輸出格式爲:n行變換後的6位密碼。

例如,輸入:
5
zhangfeng
wangximing
jiujingfazi
woaibeijingtiananmen
haohaoxuexi

則輸出:
772243
344836
297332
716652
875843

注意:

請仔細調試!您的程序只有能運行出正確結果的時候纔有機會得分!

在評卷時使用的輸入數據與試卷中給出的實例數據多是不一樣的。

請把全部函數寫在同一個文件中,調試好後,存入與【考生文件夾】下對應題號的「解答.txt」中便可。

相關的工程文件不要拷入。

源代碼中不能能使用諸如繪圖、Win32API、中斷調用、硬件操做或與操做系統相關的API。

容許使用STL類庫,但不能使用MFC或ATL等非ANSI c++標準的類庫。例如,不能使用CString類型(屬於MFC類庫)。

 解析

  這個題目基本上已經給出了程序算法的執行步驟,只要根據要求和步驟編寫代碼,基本上就能夠將問題解決

參考代碼

複製代碼
/*

心得體會: ceil((double)len/6);注意:len/6默認向下取整,只有將其強制轉換爲double類型後運算結果纔會保留小數,取整函數才發揮做用 

*/


#include<stdio.h>
#include<string.h>
#include<math.h>
#define M 10000

char input[M];
char str[M][6];
int resul[6];
int n;

int f(int a)
{
    int sum=0;
    while(a)
    {
        sum+=(a%10);
        a=a/10;
    }
    return sum;
}

int main()
{
    scanf("%d",&n);
    int i,len;
    while(n--)
    {
        memset(str,0,sizeof(str));
        scanf("%s",&input);
        len=strlen(input);
        for(i=0;i<len;i++)
        {
            str[i/6][i%6]=input[i];
        }
        
        int sum,j,row=ceil((double)len/6);
        for(i=0;i<6;i++)
        {
            sum=0;
            for(j=0;j<row;j++)
            {
                sum+=str[j][i];
            }
            resul[i]=sum;
        }
            
        for(i=0;i<6;i++)
        {
            while(1)
            {
                if(resul[i]>=0&&resul[i]<=9)break;
                resul[i]=f(resul[i]);
            }
        }
        for(i=0;i<6;i++)printf("%d",resul[i]);
        printf("\n");
    }
    
    return 0;
}
複製代碼

 《9》奪冠軍機率

問題


足球比賽具備必定程度的偶然性,弱隊也有打敗強隊的可能。

假設有甲、乙、丙、丁四個球隊。根據他們過去比賽的成績,得出每一個隊與另外一個隊對陣時取勝的機率表:

甲 乙 丙 丁 
甲 - 0.1 0.3 0.5
乙 0.9 - 0.7 0.4 
丙 0.7 0.3 - 0.2
丁 0.5 0.6 0.8 -

數據含義:甲對乙的取勝機率爲0.1,丙對乙的勝率爲0.3,...

如今要舉行一次錦標賽。雙方抽籤,分兩個組比,獲勝的兩個隊再爭奪冠軍。(參見【1.jpg】)

請你進行10萬次模擬,計算出甲隊奪冠的機率。


注意:

請仔細調試!您的程序只有能運行出正確結果的時候纔有機會得分!

在評卷時使用的輸入數據與試卷中給出的實例數據多是不一樣的。

請把全部函數寫在同一個文件中,調試好後,存入與【考生文件夾】下對應題號的「解答.txt」中便可。

相關的工程文件不要拷入。

源代碼中不能能使用諸如繪圖、Win32API、中斷調用、硬件操做或與操做系統相關的API。

容許使用STL類庫,但不能使用MFC或ATL等非ANSI c++標準的類庫。例如,不能使用CString類型(屬於MFC類庫)。

 

 分析

   此題主要就是在模擬算法中,要藉助rand()函數產生隨機數,rand()的用法和比賽規則,基本上解題就沒有太大問題了。

參考代碼

複製代碼
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

float rate[][6]={{0,1,3,5},
         {9,0,7,4},
         {7,3,0,2},
         {5,6,8,0}};

int main()
{
    int a,a1,b,b1,i,count=0;
    
    srand(time(NULL));//隨機重在在for循環外 
    for(i=0;i<100000;i++)
    {
        a1=1+rand()%3;//產生從1~3的隨機數,既產生a(甲)的對手
        if(rand()%10<rate[0][a1])//a勝;rand()%10,產生0~9的隨機數
        {
            switch(a1)
            {
                case 1:
                    b=2;
                    b1=3;
                    break;
                case 2:
                    b=1;
                    b1=3;
                    break;
                case 3:
                    b=1;
                    b1=2;
                    break;
                default:
                    break;
            }
            if(rand()%10<rate[b][b1])//b勝 
            {
                a1=b;
            }
            else a1=b1;
            if(rand()%10<rate[0][a1])count++;
        }
    }
    
    printf("%f\n",count*1.0/100000);
    
    return 0;
} 
複製代碼

 

 《10》取球遊戲

問題


今盒子裏有n個小球,A、B兩人輪流從盒中取球,每一個人均可以看到另外一我的取了多少個,也能夠看到盒中還剩下多少個,而且兩人都很聰明,不會作出錯誤的判斷。

咱們約定:

每一個人從盒子中取出的球的數目必須是:1,3,7或者8個。

輪到某一方取球時不能棄權!

A先取球,而後雙方交替取球,直到取完。

被迫拿到最後一個球的一方爲負方(輸方)

請編程肯定出在雙方都不判斷失誤的狀況下,對於特定的初始球數,A是否能贏?

程序運行時,從標準輸入得到數據,其格式以下:

先是一個整數n(n<100),表示接下來有n個整數。而後是n個整數,每一個佔一行(整數<10000),表示初始球數。

程序則輸出n行,表示A的輸贏狀況(輸爲0,贏爲1)。

例如,用戶輸入:



10
18

則程序應該輸出:
0
1
1
0

 

注意:

請仔細調試!您的程序只有能運行出正確結果的時候纔有機會得分!

在評卷時使用的輸入數據與試卷中給出的實例數據多是不一樣的。

請把全部函數寫在同一個文件中,調試好後,存入與【考生文件夾】下對應題號的「解答.txt」中便可。

相關的工程文件不要拷入。

源代碼中不能能使用諸如繪圖、Win32API、中斷調用、硬件操做或與操做系統相關的API。

容許使用STL類庫,但不能使用MFC或ATL等非ANSI c++標準的類庫。例如,不能使用CString類型(屬於MFC類庫)。

 分析

  這是一個動態規劃問題,設flag[i]表示初始球數爲 i 時A的勝負狀況,當flag[i]==0的時候表示負,否在表示贏。每次容許拿的球K={1,3,7,8},此外,顯然flag[1]=0。

如今要求初始球數爲x的時候,A的勝負狀況,而A先取球,則第一次取球K,只要檢查flag[x-K]的勝負狀況既可知道flag[x],若flag[x-K]==0則flag[x-K]=1,若檢查完全部的K都沒法

找到這樣的狀況,則表示flag[x-k]=0.

參考代碼

複製代碼
#include<stdio.h>
#include<string.h>
#define M1 10010
#define M2 110
int main()
{
    int n,i,j,max,a[M2],flag[M1],b[]={1,3,7,8};
    
    memset(flag,0,sizeof(flag));//能夠在定義flag時進行初始化,既然int flag[M1]={0};
    scanf("%d",&n);
    max=-1;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]>max)max=a[i];//記錄下初始球數最多的數目
    }
    
    for(i=2;i<=max;i++)//動態規劃
    {
        for(j=0;j<4&&b[j]<i;j++)//嘗試全部可行的取球方案,既要取走的球數必須小於當前存有的球數
        {
            if(flag[i-b[j]]==0)//拿走b[j]個球后的狀態若爲輸則如今A拿走b[j]個球就是能夠贏 
            {
                flag[i]=1;
                break;
            }
        }
    } 
    
    for(i=1;i<=n;i++)
    {
        printf("%d\n",flag[a[i]]);
    }
    
    return 0;
}
相關文章
相關標籤/搜索