藍橋杯-帶分數

小程xy發表於2024-05-06

100 可以表示為帶分數的形式:100 = 3 + 69258/714
還可以表示為:100 = 82 + 3546 / 197
注意特徵:帶分數中,數字 1∼9 分別出現且只出現一次(不包含 0)。

類似這樣的帶分數,100 有 11 種表示法。

輸入格式

一個正整數。

輸出格式

輸出輸入數字用數碼 1∼9 不重複不遺漏地組成帶分數表示的全部種數。

資料範圍

1≤N<1e6

輸入樣例1:

100

輸出樣例1:

11

輸入樣例2:

105

輸出樣例2:

6

題解:

  • 列舉所有 a 的情況, 在每種 a 的前提下, 再列舉所有 c 的情況
  • 根據 a, c, n 計算出 b
  • 判斷是否滿足 [1, 9] 僅出現過一次, 且 a, b, c中不含有0

程式碼並不是很長, 去除空行大概有五十行, 大家耐心看, 程式碼中有很多註釋, 如果有不理解的地方可以再問~

#include <bits/stdc++.h>
using namespace std;
const int N = 20;
int n, ans;
bool st[N], back[N];

bool check(int a, int c)
{
    int b = n * c - a * c;  // 公式: n = a + b / c  ==> b = n * c - a * c

    if (!a || !b || !c) return false;  //  會把 a b c 任意一個等於 0 的情況給篩掉

    memcpy(back, st, sizeof st);    // 賦值st的狀態, 用於判斷 [1, 9] 是否全出現過
    while (b)
    {
        int x = b % 10;     // 取個位
        b /= 10;    // 個位刪掉
        if (!x || back[x]) return false;  // 保證 b 中不含 0, 同時 保證 [1, 9] 只出現過一次
        back[x] = true;
    }
    for (int i = 1; i <= 9; i ++) if (back[i] == false) return false;
    return true;
}

void dfs_c(int u, int a, int c)
{
    if (check(a, c)) ans ++;  //  這裡同樣可以不用管 c 是否為 0, check函式中有 處理 c 等於 0 的情況

    for (int i = 1; i <= 9; i ++)
    {
        if (st[i]) continue;
        st[i] = true;
        dfs_c(u + 1, a, c * 10 + i);
        st[i] = false;
    }
}

void dfs_a(int u, int a)  // 列舉 a 的所有可以能 (1, 12, 123, ... 987654321)
{
    if (a > n) return;   // 剪枝, a > n的時候 b,c沒有滿足條件的值 (沒有這個也不會死迴圈, 有這個可以減少程式碼執行的時間)

    if(a != 0) dfs_c(u, a, 0);  // 這和判斷可以寫, 也可以不寫, 寫的話執行時間會快一些, 不寫的話在check函式中對 等於 0 進行的處理
    
    for (int i = 1; i <= 9; i ++)  
    {
        if (st[i]) continue;
        st[i] = true;
        dfs_a(u + 1, a * 10 + i);
        st[i] = false;
    }
}

int main()
{
    cin >> n;
    
    dfs_a(0, 0);
    
    cout << ans << endl;
    return 0;
}

覺得寫的不錯的話, 點個贊吧~