1. 程式人生 > >藍橋杯第五屆題目求解

藍橋杯第五屆題目求解

第四題

題目

  • 今有7對數字:兩個1,兩個2,兩個3,…兩個7,把它們排成一行。
    要求,兩個1間有1個其它數字,兩個2間有2個其它數字,以此類推,兩個7之間有7個其它數字。如下就是一個符合要求的排列:
    17126425374635
    當然,如果把它倒過來,也是符合要求的。
    請你找出另一種符合要求的排列法,並且這個排列法是以74開頭的。
    注意:只填寫這個14位的整數,不能填寫任何多餘的內容,比如說明註釋等。

程式碼

#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <stdio.h>
using namespace std;

int res[14];  // 最終的排序結果 
int t[7]; // 7個數的使用次數 

void dfs( int x )
{
    if( x == 14 )
    {
        for(int i=0;i<14;i++)
            printf("%d", res[i]);
        printf("\n");
        return;
    }
    for(int i=0;i<7;i++)
    {
        if( t[i] <= 0 )
            continue;
        if( t[i] == 2 )
        {
            t[i]--;
            res[x] = i+1;
            dfs( x+1 );
            t[i]++;
        }
        else if(t[i] == 1)
        {
            if( i+2<=x && i+1 == res[x-i-2] )
            {
                t[i]--;
                res[x] = i+1;
                dfs( x+1 );
                t[i]++;
            }
        }   
    }
}

int main()
{
    for(int i=0;i<7;i++)
        t[i] = 2; // 初始2次
    res[0] = 7;
    res[1] = 4;
    t[3] = 1;
    t[6] = 1;
    dfs( 2 );
    return 0;
} 

* 注:只用DFS求解即可。

第六題

題目

  • 你一定聽說過“數獨”遊戲。
    如【圖1.png】,玩家需要根據9×9盤面上的已知數字,推理出所有剩餘空格的數字,並滿足每一行、每一列、每一個同色九宮內的數字均含1-9,不重複。

數獨的答案都是唯一的,所以,多個解也稱為無解。

本圖的數字據說是芬蘭數學家花了3個月的時間設計出來的較難的題目。但對會使用計算機程式設計的你來說,恐怕易如反掌了。

本題的要求就是輸入數獨題目,程式輸出數獨的唯一解。我們保證所有已知資料的格式都是合法的,並且題目有唯一的解。

格式要求:
輸入9行,每行9個數字,0代表未知,其它數字為已知。
輸出9行,每行9個數字表示數獨的解。

程式碼

  • 使用DFS就可以直接求解
  • src.txt中的內容是

    005300000
    800000020
    070010500
    400005300
    010070006
    003200080
    060500009
    004000030
    000009700
    
  • #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <string.h>
    #include <stdio.h>
    using namespace std;
    int a[9][9];
    
    // 判斷行與列是否為重複 
    bool noRepeatRowCol(int r, int c, int val)
    {
        for(int i=0;i<9;i++)
            if( a[i][c] == val )
                return false;
        for(int i=0;i<9;i++)
            if( a[r][i] == val )
                return false;
        return true;
    }
    
    // 判斷一個小的3X3方格中是否重複 
    bool noRepeatBox(int r, int c, int val)
    {
        int r1 = r/3, c1=c/3;
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<3;j++)
            {
                if( a[r1*3+i][c1*3+j] == val )
                    return false;
            }
        }
        return true;
    }
    
    // 輸出九宮格的資訊 
    void print()
    {
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
                cout << a[i][j];
            cout << endl;
        }
    }
    
    void dfs(int r, int c)
    {
        if( r >= 9 )
        {
            print();
            return;
        }
    
        if( a[r][c] == 0 )
        {
            for(int i=1;i<=9;i++)
            {
                if( noRepeatRowCol(r,c,i) && noRepeatBox(r,c,i) )
                {
                    a[r][c] = i;
                    dfs( r+(c+1)/9, (c+1)%9 );
                    a[r][c] = 0;
                }
            }
        }
        else
        {
            dfs( r+(c+1)/9, (c+1)%9 );
        }
    }
    
    int main()
    {
        char s[10][10];
        FILE *fp = fopen("src.txt","r");
        for(int i=0;i<9;i++)
        {
            fscanf(fp,"%s",&s[i]);
        }
        fclose( fp );
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                a[i][j] = s[i][j] - 48;
    
        dfs(0,0);
    
        return 0;
    } 
    

第七題

題目

G將軍有一支訓練有素的軍隊,這個軍隊除開G將軍外,每名士兵都有一個直接上級(可能是其他士兵,也可能是G將軍)。現在G將軍將接受一個特別的任務,需要派遣一部分士兵(至少一個)組成一個敢死隊,為了增加敢死隊隊員的獨立性,要求如果一名士兵在敢死隊中,他的直接上級不能在敢死隊中。
請問,G將軍有多少種派出敢死隊的方法。注意,G將軍也可以作為一個士兵進入敢死隊。
輸入格式
輸入的第一行包含一個整數n,表示包括G將軍在內的軍隊的人數。軍隊的士兵從1至n編號,G將軍編號為1。
接下來n-1個數,分別表示編號為2, 3, …, n的士兵的直接上級編號,編號i的士兵的直接上級的編號小於i。
輸出格式
輸出一個整數,表示派出敢死隊的方案數。由於數目可能很大,你只需要輸出這個數除10007的餘數即可。
樣例輸入1
3
1 1
樣例輸出1
4
樣例說明
這四種方式分別是:
1. 選1;
2. 選2;
3. 選3;
4. 選2, 3。
樣例輸入2
7
1 1 2 2 3 3
樣例輸出2
40

資料規模與約定
對於20%的資料,n ≤ 20;
對於40%的資料,n ≤ 100;
對於100%的資料,1 ≤ n ≤ 100000。

資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 2000ms

請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。

所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。

注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。

提交時,注意選擇所期望的編譯器型別。

程式碼

#include <iostream>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <stdio.h>
using namespace std;

int N;

// a[i]=n表示士兵i的上級為n 
int a[100005];
// 標記位,判斷士兵i是否在當前的隊伍中 
bool isin[100005];

int sum = 0;

bool tmp = false;

void dfs(int n)
{
    if( n > N )
        return;

    tmp = true;
    for(int i=1;i<n;i++)
    {
        if( isin[i] && (a[i]==n || a[n]==i) )
        {
            tmp = false;
            break;
        }
    }
    // 下標為n的士兵可以插入到當前敢死隊中,與之前的隊伍不衝突 
    if( tmp )
    {
        sum = (sum+1) % 10007;
        isin[n] = true;
        dfs( n+1 );
        isin[n] = false;
    }
    // 不加入當前士兵是另一種方法
    dfs( n+1 );

}

int main()
{
    scanf("%d", &N);
    for(int i=2;i<=N;i++)
        scanf("%d", &a[i]);
    a[1] = -1; // 將軍沒有上級 

    for(int i=1;i<N;i++)
        isin[i] = false;
    dfs( 1 );
    cout << sum << endl;

    return 0;
}