1. 程式人生 > 實用技巧 >暴力演算法

暴力演算法

暴力演算法

1. 演算法分析

    很多時候題目資料量不是很大的時候都可以暴力處理。

2. 例題

acwing116飛行員兄弟
題意: “飛行員兄弟”這個遊戲,需要玩家順利的開啟一個擁有16個把手的冰箱。已知每個把手可以處於以下兩種狀態之一:開啟或關閉。只有當所有把手都開啟時,冰箱才會開啟。把手可以表示為一個4х4的矩陣,您可以改變任何一個位置[i,j]上把手的狀態。但是,這也會使得第i行和第j列上的所有把手的狀態也隨著改變。請你求出開啟冰箱所需的切換把手的次數最小值是多少。
題解: 由於按鍵相當於異或,因此按鍵的順序無所謂。本題只有16個按鍵,可以直接暴力所有的情況,然後先預處理要異或的值,就可以在每次暴力的時候O(1)查詢最後的結果。
程式碼:

#include <bits/stdc++.h>

using namespace std;

int change[10][10];
int state, now;

int get(int x, int y) {
    return x * 4 + y;
}

int main() {
    // 預處理異或的情況
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            for (int k = 0; k < 4; ++k) 
                change[i][j] += (1 << get(i, k)) + (1 << get(k, j));
            change[i][j] -= (1 << get(i, j));
        }
    }
    
    // state表示當前矩陣的狀態
    for (int i = 0; i < 4; ++i) {
        string line;
        cin >> line;
        for (int j = 0; j < 4; ++j) {
            if (line[j] == '+') state += (1 << get(i, j));
        }
    }
    
    vector<pair<int, int> > res;
    for (int i = 0; i < 1 << 16; ++i) {  // 暴力列舉所有的狀態
        vector<pair<int, int> > tmp;
        int now = state;
        for (int j = 0; j < 16; ++j) {  // 判斷當前按鍵內每個點的狀態
            if (i >> j & 1 ) {
                int x = j / 4, y = j % 4;
                now ^= change[x][y];
                tmp.push_back({x, y});
            }
        }
        
        // 最後的末狀態要0才能更新
        if (!now && (res.empty() || res.size() > tmp.size())) res = tmp;
    }
    
    cout << res.size() << endl;
    for (auto r: res) cout << r.first + 1 << " " << r.second + 1 << endl;
    return 0;
}

acwing1209 帶分數
題意: 100 可以表示為帶分數的形式:100 = 3+ \(\frac{69258}{714}\)
還可以表示為:100 = 82 + \(\frac{3546}{197}\)
注意特徵:帶分數中,數字 1∼9 分別出現且只出現一次(不包含 0)。
類似這樣的帶分數,100 有 11 種表示法。
給定n,求n的帶分數的表示法數目。
1 ≤ n < 10^6^
題解: 1 ~ 9每個數字只能出現一次,那麼全排列一共有9!種,可以暴力將9個數字拆分為abc,然後判斷是否組成的帶分數為n即可。時間複雜度: 9! * 9^3^
程式碼:

#include <bits/stdc++.h>

using namespace std;

int res = 0;
int n;
vector<int> num;

void check() {
    int a = 0, b = 0, c = 0;
    for (int i = 1; i <= 7; ++i) {  // a的長度
        for (int j = 1; j <= 7; ++j) {  // b的長度
            int k = 9 - i - j;  // c的長度
            if (k <= 0) continue;
            a = 0, b = 0, c = 0;
            int pos = 0;
            for (int l = 0; l < i; ++l) a = a * 10 + num[pos++];  // a
            if (a > n) continue;
            for (int l = 0; l < j; ++l) b = b * 10 + num[pos++];  // b
            for (int l = 0; l < k; ++l) c = c * 10 + num[pos++];  // c
            if (b % c == 0 && a + b / c == n) {  // 判斷是否為n
                res++;
            }
        }
    }
    return;
}

int main() {
    cin >> n;
    num.push_back(1);
    num.push_back(2);
    num.push_back(3);
    num.push_back(4);
    num.push_back(5);
    num.push_back(6);
    num.push_back(7);
    num.push_back(8);
    num.push_back(9);
    check();
    while (next_permutation(num.begin(), num.end())) check();  // 遍歷全排列
    cout << res << endl;
    return 0;
}