機試題練習(2012年-2007年)

2012年

1.1322求子集重量之和

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    vector<int> v;
    cin >> n;
    int m = n;
    while (m--)
    {
        int x;
        cin >> x;
        v.push_back(x);
    }
    int sum = 0;
    for (int j = 0; j < n; j++)
    {
        bool i;
        cin >> i;
        if (i == 1)
        {
            sum += v[j];
        }
    }
    cout << sum;
    system("pause");
    return 0;
}

2.1054字符串統計

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    getline(cin, s);
    int alpha = 0, num = 0, blank = 0, others = 0;
    for (auto i : s)
    {
        if (isdigit(i))
        {
            num++;
        }
        else if (isalpha(i))
        {
            alpha++;
        }
        else if (i == ' ')
        {
            blank++;
        }
        else
        {
            others++;
        }
    }
    cout << alpha << " " << blank << " " << num << " " << others << endl;
    system("pause");
    return 0;
}

3.1082花生米系列

1.k任取

共有n粒,輸入n,甲先取k粒,乙再取k粒如此反覆,直到乙取走最後一粒。輸出k,若無解則輸出0.0<k<10、0<n<=1000
暴力法:k取值有10種,從k=9開始嘗試,成功就停止循環,不行k=8……都不行輸出0(事實上除了n=1之外都有解,我做的有錯嗎?)
兩人是否必須取滿k粒??此題擱置,在noj系統中提交時候再解

#include <bits/stdc++.h>
using namespace std;
bool isOk(int n, int k)
{
    if (n <= k)
        return 0;
    if (n == 2)
    {
        cout << n << "  1" << endl;
        return 1;
    }
    int quotient = n / k;
    int remainder = n % k;
    if (quotient % 2 == 0 and remainder == 0)
    {
        cout << n << "  " << k << endl;
        return 1;
    }

    return 0;
}
int main()
{
    for (int j = 1; j < 1000; j++)
    {
        int flag = 1;
        for (int i = 9; i > 0; i--)
        {
            if (isOk(j, i))
            {
                flag = 0;
                break;
            }
        }
        if (flag == 1)
            cout << j << "  0" << endl;
    }
    system("pause");
    return 0;
}

https://blog.csdn.net/qq_41727666/category_9279609.html

2.k=1或5或10

4.1091求解逆波蘭表達式

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string s;
    getline(cin, s);
    stack<int> st;
    int first, second;
    for (auto i : s)
    {
        if (isdigit(i))
        {
            st.push(i - '0');
        }
        else
        {
            second = st.top();
            st.pop();
            first = st.top();
            st.pop();
            switch (i)
            {
            case '*':
                st.push(first * second);
                break;
            case '/':
                st.push(first / second);
                break;
            case '+':
                st.push(first + second);
                break;
            case '-':
                st.push(first - second);
                break;
            }
        }
    }
    cout << st.top() << endl;
    system("pause");
    return 0;
}

5.1021柱狀圖

#include <bits/stdc++.h>
using namespace std;
int main()
{
    map<char, int> mp;
    for (int i = 0; i < 26; i++)
    {
        mp[char('A' + i)] = 0;
    }
    int max = -1;
    char maxc;
    for (int i = 0; i < 4; i++)
    {
        string s;
        getline(cin, s);
        for (auto i : s)
        {
            if (i >= 'A' and i <= 'Z')
            {
                mp[i]++;
                if (mp[i] > max)
                {
                    max = mp[i];
                    maxc = i;
                }
            }
        }
    }
    char show[max + 1][26];
    for (int i = 0; i < max + 1; i++)
    {
        for (int j = 0; j < 26; j++)
        {
            show[i][j] = ' ';
        }
    }
    for (auto i : mp)
    {
        //cout << i.first << " " << i.second << endl;
        for (int j = max; j > max - i.second; j--)
        {
            show[j][int(i.first - 'A')] = '*';
        }
    }
    for (int i = 1; i < max + 1; i++)
    {
        for (int j = 0; j < 26; j++)
        {
            if (j == 0)
                cout << show[i][j];
            else
                cout << " " << show[i][j];
        }
        cout << endl;
    }
    for (int i = 0; i < 25; i++)
    {
        cout << char(i + 'A') << " ";
    }
    cout << 'Z' << endl;
    system("pause");
    return 0;
}

6.1028判斷三角形

根據三角形“兩邊之和大於第三邊,兩邊之差小於第三邊”來判斷

7.1147木乃伊迷宮

沒做。挖坑。

8.數獨遊戲

數獨遊戲規則
在9階方陣中,包含了81個小格(九列九行),其中又再分成九個小正方形(稱爲宮),每宮有九小格。
遊戲剛開始時,盤面上有些小格已經填了數字(稱爲初盤),遊戲者要在空白的小格中填入1到9的數字,
使得最後每行、每列、每宮都不出現重複的數字,而且每一個遊戲都只有一個唯一的解答(稱爲終盤)。

輸入
一個9*9的矩陣,0表示該位置是空白。

輸出
一個9*9的矩陣,格式與輸入類似。

輸入樣例
900050060
020070100
300102040
703800529
000345000
516009403
050208006
007090010
030010004

輸出樣例
971453268
428976135
365182947
743861529
892345671
516729483
154238796
687594312
239617854
思路:DFS+剪枝,每個DFS函數處理一格子,不能填入的或全部填滿則函數終止,其他情況dfs函數處理下一格子。

#include <bits/stdc++.h>
using namespace std;
int b[9][9];
bool isValid(int x, int y, int num)
{
    for (int i = 0; i < 9; i++)
    {
        if (b[i][y] == num)
            return 0;
        if (b[x][i] == num)
            return 0;
    }
    int x0 = x / 3, y0 = y / 3;
    for (int i = 3 * x0; i < 3 * x0 + 3; i++)
    {
        for (int j = 3 * y0; j < 3 * y0 + 3; j++)
        {
            if (b[i][j] == num)
                return 0;
        }
    }
    return 1;
}
void dfs(int row, int col)
{
    if (row == 8 and col == 8)
    {
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                cout << b[i][j];
            }
            cout << endl;
        }
        return;
    }
    if (b[row][col] != 0) //不能填入的 往前走一個格
    {
        if (col < 8)
        {
            dfs(row, col + 1);
        }
        else if (col == 8)
        {
            dfs(row + 1, 0);
        }
    }
    else
    {
        bool flag = 1;
        for (int n = 1; n <= 9; n++)
        {
            if (isValid(row, col, n))
            {
                b[row][col] = n;
                flag = 0;
                if (col < 8)
                {
                    dfs(row, col + 1);
                }
                else if (col == 8)
                {
                    dfs(row + 1, 0);
                }
                b[row][col] = 0; //撤銷掉 就像沒填過一樣
            }
        }
        if (flag == 1) //一個都填不進去 返回
            return;
    }
}
int main()
{
    for (int i = 0; i < 9; i++)
    {
        string s;
        getline(cin, s);
        for (int j = 0; j < 9; j++)
        {
            b[i][j] = s[j] - '0';
        }
    }
    dfs(0, 0);
    system("pause");
    return 0;
}

2011年

1.斐波那契數列

在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
int dp[21];
void outPut(int n)
{
    int flag = 1;
    while (n >= 1)
    {
        for (int i = 20; i >= 1; i--)
        {
            if (n >= dp[i])
            {
                if (flag == 1)
                {
                    cout << dp[i];
                    n -= dp[i];
                    flag = 0;
                }
                else
                {
                    cout << "+" << dp[i];
                    n -= dp[i];
                }
            }
        }
    }
}
int main()
{
    int n;
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i < 21; i++)
    {
        dp[i] = dp[i - 1] + dp[i - 2];
        //cout << i << " " << dp[i] << endl;
    }
    while (cin >> n && n != 0)
    {
        cout << n << "=";
        outPut(n);
        cout << endl;
    }
    system("pause");
    return 0;
}

2.打印楊輝三角

在這裏插入圖片描述
注意memset函數用法int b[K][2 * K - 1]; memset(b, 0, sizeof(b));

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int K;
    cin >> K;
    int b[K][2 * K - 1];
    memset(b, 0, sizeof(b));
    b[0][K - 1] = 1;
    for (int i = 0; i < 2 * K - 1; i++)
    {
           if (b[0][i] == 0)
            {
                cout << " " << " ";
            }else{
                cout<<b[0][i]<<" ";
            }
    }
    cout << endl;
    for (int i = 1; i < K; i++)
    {
        for (int j = 0; j < 2 * K - 1; j++)
        {
            if (j - 1 >= 0 and j + 1 < 2 * K - 1)
            {
                b[i][j] = b[i - 1][j - 1] + b[i - 1][j + 1];
            }
            if (i + j == K - 1 or j - i == K - 1)
            {
                b[i][j] = 1;
            }
            if (b[i][j] == 0)
            {
                cout << " " << " ";
            }else{
                cout<<b[i][j]<<" ";
            }
        }
        cout << endl;
    }
    system("pause");
    return 0;
}

3.調整N階方陣的主元@@@

在這裏插入圖片描述在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
ostream &operator<<(ostream &out, const vector<vector<int>> v)
{
    for (int i = 0; i < v.size(); i++)
    {
        for (int j = 0; j < v.size(); j++)
        {
            out << v[i][j] << " ";
        }
        out << endl;
    }
    return out;
}
void transfer(vector<vector<int>> &v)
{
    for (int t = 0; t < v.size(); t++)
    {
        int max = -1, flag;
        for (int i = t; i < v.size(); i++)
        {
            if (v[i][0] > max)
            {
                max = v[i][0];
                flag = i;
            }
            swap(v[t], v[flag]);
        }
    }
}
int main()
{
    ifstream inf; //infile
    inf.open(R"(H:\matrix.txt)");
    if (!inf.is_open())
    {
        cout << "cant open file.";
        return -1;
    }
    while (inf.good())
    {
        int N;
        inf >> N;
        if (N == 0)
            break;
        vector<vector<int>> v(N, vector<int>(N, 0));
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                int x;
                inf >> x;
                v[i][j] = x;
            }
        }
        transfer(v);
        cout << v << endl;
    }
    inf.close();
    system("pause");
    return 0;
}

matrix.txt文件內容爲:

4
1 2 3 4
5 6 7 8
2 3 4 5
1 3 4 6
8
12 23 43 12 23 45 64 61
34 54 12 34 89 16 40 34
34 54 12 54 71 12 65 34
54 32 66 54 51 47 16 73
26 34 63 14 65 35 76 23
12 45 63 73 62 56 76 15
67 23 90 89 73 71 81 21
12 56 80 91 33 54 12 56
2
1 2
2 1
1
1
0

4.合併字符串

在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s1, s2;
    getline(cin, s1);
    getline(cin, s2);
    string s = "";
    reverse(s2.begin(), s2.end());
    if (s1.size() >= s2.size())
    {
        for (int i = 0; i < s1.size(); i++)
        {
            if (i < s2.size())
            {
                s += s1[i];
                s += s2[i];
            }
            else
            {
                s += s1[i];
            }
        }
    }
    else
    {
        for (int i = 0; i < s2.size(); i++)
        {
            if (i < s1.size())
            {
                s += s1[i];
                s += s2[i];
            }
            else
            {
                s += s2[i];
            }
        }
    }
    cout << s << endl;
    system("pause");
    return 0;
}

5.多項式加法

在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ifstream inf;
    inf.open(R"(H:\polyn.txt)");
    if (!inf.is_open())
    {
        cout << "can not open.";
    }
    while (1)
    {
        map<int, int, greater<int>> mp;
        mp.erase(mp.begin(), mp.end());
        int n1, n2;
        inf >> n1;
        for (int i = 0; i < n1; i++)
        {
            int a, b;
            inf >> a >> b;
            mp[b] += a;
        }
        inf >> n2;
        for (int i = 0; i < n2; i++)
        {
            int a, b;
            inf >> a >> b;
            mp[b] += a;
        }
        if (n1 == 0 and n2 == 0)
            break;
        for (auto i : mp)
        {
            cout << i.second << " " << i.first << " ";
        }
        cout<<endl;
    }
    system("pause");
    return 0;
}

polyn.txt:

3 3 5 -2 1 4 0
4 2 3 -1 2 1 1 3 0
3 1 2 1 1 1 0
3 2 2 2 1 2 0
0
0

2010年

1.1041.最長公共子序列(DP)@@@

學習https://blog.csdn.net/bitcarmanlee/article/details/88977705

  • 定義狀態:
    DP[i][j]表示,串1以第i個字符結尾、串2以第j個字符結尾時,他們的最長公共子序列。例如asdf和aspq,DP[1][1]=1、DP[1][2]=1、DP[2][2]=2
  • 定義狀態轉移方程
    在這裏插入圖片描述
    代碼非常好寫,主要是上面的狀態方程得弄清楚了
#include <bits/stdc++.h>
using namespace std;
int main()
{
    while (1)
    {
        string s1, s2;
        getline(cin, s1, ' ');
        getline(cin, s2);
        if (s1.size() == 0 or s2.size() == 0)
            break;//本題沒說退出條件是怎樣的
        s1.insert(s1.begin(), 'x');
        s2.insert(s2.begin(), 'x');//填充無用字符
        int dp[s1.size()][s2.size()];
        for (int i = 0; i < s1.size(); i++)
        {
            for (int j = 0; j < s2.size(); j++)
            {
                if (i == 0 or j == 0)
                    dp[i][j] = 0;
                else
                {
                    if (s1[i] == s2[j])
                    {
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    }
                    else
                    {
                        dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                    }
                }
            }
        }
        cout << dp[s1.size() - 1][s2.size() - 1] << endl;
    }
    system("pause");
    return 0;
}

再來看看最長公共子串的情況,也就是說字符串必須連續的情況,只需要改變狀態轉移方程即可:
在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
int main()
{
    while (1)
    {
        string s1, s2;
        int max = -1;
        getline(cin, s1, ' ');
        getline(cin, s2);
        if (s1.size() == 0 or s2.size() == 0)
            break; //本題沒說退出條件是怎樣的
        s1.insert(s1.begin(), 'x');
        s2.insert(s2.begin(), 'x'); //填充無用字符
        int dp[s1.size()][s2.size()];
        for (int i = 0; i < s1.size(); i++)
        {
            for (int j = 0; j < s2.size(); j++)
            {
                if (i == 0 or j == 0)
                    dp[i][j] = 0;
                else
                {
                    if (s1[i] == s2[j])
                    {
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    }
                    else
                    {
                        dp[i][j] = 0;
                    }
                }
                dp[i][j] > max ? max = dp[i][j] : NULL;
            }
        }
        cout << max << endl;
    }
    system("pause");
    return 0;
}

2.1144農場灌溉問題(DFS)@@@

在這裏插入圖片描述
首先我的思路是深搜,看了眼1441連陰雨這道題的解法,發現其實是同一題:

  • 標記數組用來存每個格子的髒位
  • 對每個格子用dfs函數,儘可能地標記附近的格子,即水流能流到的格子(深搜)
  • 遍歷每個格子
    • 如果未被標記,調用bfs,計數器加1,因爲附近的格子的水沒流到此格子
    • 如果被標記,說明附近格子的水流到此格子,計數器不用加,此格子直接略過不調用bfs函數
  • 遍歷完畢了,計數器的值就是離散水坑的值。

如果我還沒說明白,舉個例子:地圖上所有點都連在了一起(水流覆蓋全圖),bfs第一個點時,其他所有點都會被標記,主函數裏計數器值等於1。此時繼續遍歷其他點,發現被標記什麼也不做,那麼計數器值不變還是1。說明全圖只有一個水坑。

#include <bits/stdc++.h>
using namespace std;
unordered_map<char, array<bool, 4>> mp; //上下左右可前進表
void dfs(int x, int y, vector<vector<char>> &b, vector<vector<bool>> &mark)
{
    mark[x][y] = 1;
    int m = b.size();
    int n = b[0].size();
    if (mp[b[x][y]][0] == 1 and (x - 1) >= 0 and mp[b[x - 1][y]][1] == 1 and mark[x - 1][y] == 0)
        dfs(x - 1, y, b, mark);
    if (mp[b[x][y]][1] == 1 and (x + 1) < m and mp[b[x + 1][y]][0] == 1 and mark[x + 1][y] == 0)
        dfs(x + 1, y, b, mark);
    if (mp[b[x][y]][2] == 1 and (y - 1) >= 0 and mp[b[x][y - 1]][3] == 1 and mark[x][y - 1] == 0)
        dfs(x, y - 1, b, mark);
    if (mp[b[x][y]][3] == 1 and (y + 1) < n and mp[b[x][y + 1]][2] == 1 and mark[x][y + 1] == 0)
        dfs(x, y + 1, b, mark);
}
int main()
{
    //誰能告訴我更簡單的插入方法?
    mp.insert({'A', {1, 0, 1, 0}});
    mp.insert({'B', {1, 0, 0, 1}});
    mp.insert({'C', {0, 1, 1, 0}});
    mp.insert({'D', {0, 1, 0, 1}});
    mp.insert({'E', {1, 1, 0, 0}});
    mp.insert({'F', {0, 0, 1, 1}});
    mp.insert({'G', {1, 0, 1, 1}});
    mp.insert({'H', {1, 1, 1, 0}});
    mp.insert({'I', {0, 1, 1, 1}});
    mp.insert({'J', {1, 1, 0, 1}});
    mp.insert({'K', {1, 1, 1, 1}});
    while (1)
    {
        int m, n;
        cin >> m >> n;
        if (m == -1 and n == -1)
            break;
        cin.get();//喫空格
        vector<vector<char>> b(m, vector<char>(n, '?'));  //棋盤
        vector<vector<bool>> mark(m, vector<bool>(n, 0)); //標記
        for (int i = 0; i < m; i++)
        {
            string s;
            getline(cin, s, ' ');
            for (int j = 0; j < s.size(); j++)
            {
                b[i][j] = s[j];
            }
        }
        int count = 0;
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (mark[i][j] == 1)
                    continue;       //如果點都標記過 count不用加
                dfs(i, j, b, mark); //標記儘可能走到的點
                count++;
            }
        }
        cout << count << " ";
    }
    cout<<endl;
    system("pause");
    return 0;
}

總結,這是一個dfs經典題,需要多鑽研。

3.迴文質數

因爲151既是一個質數又是一個迴文數(從左到右和從右到左是看一樣的),所以 151 是迴文質數。

寫一個程序來找出範圍[a,b](5 <= a < b <= 100,000,000)( 一億)間的所有迴文質數;

Input:
多組輸入數據

第 1 行: 二個整數 a 和 b .

Output:
輸出一個迴文質數的列表,一行一個。

Sample Input:
5 500
Sample Output:
5
7
11
101
131
151
181
191
313
353
373
383
注意判斷質數的方法!

#include <bits/stdc++.h>
using namespace std;
bool is_prime(long x)
{
    int k = sqrt(x);
    for (int i = 2; i <= k; i++)
    {
        if (x % i == 0)
            return 0;
    }
    return 1;
}
bool is_huiwen(long x)
{
    string s = "";
    while (x)
    {
        s += x % 10 + '0';
        x /= 10;
    }
    string ss = s;
    reverse(s.begin(), s.end());
    return s == ss;
}
int main()
{
    long a, b;
    cin >> a >> b;
    for (int i = a; i <= b; i++)
    {
        if (is_huiwen(i) and is_prime(i))
        {
            cout << i << endl;
        }
    }
    system("pause");
    return 0;
}

接下來我想測試下,是先判斷迴文數還是先判斷質數,程序會快一定,我把main函數改了

int main()
{
    clock_t start = clock();
    int a = 5, b = 10000000;
    int count = 0;
    for (int i = a; i <= b; i++)
    {
        if (is_prime(i) and is_huiwen(i))
        {
   //衆所周知,is_prime函數返回0後,is_huiwen函數將不會執行
            count++;//無意義語句
        }
    }
    clock_t finish = clock();
    cout << "time consming:" << finish - start << endl;
    system("pause");
    return 0;
}

多次運算取平均值:先判斷質數時,輸出6947,先判斷迴文數時,輸出7951。多了1000個cpu時鐘週期。

clock()是C/C++中的計時函數,而與其相關的數據類型是clock_t。

它的具體功能是返回處理器調用某個進程或函數所花費的時間。函數返回從“開啓這個程序進程”到“程序中調用clock()函數”時之間的CPU時鐘計時單元(clock tick)數

在這裏插入圖片描述
我的cpu主頻是2.5GHz,1000個時鐘週期是400ns=0.4us,影響不大,但是說明先判斷質數會快一點,可能因爲isprime函數返回0要多一些,即非質數多於非迴文數。

4.1005裝載問題??

參考這裏
描述
有兩艘船,載重量分別是c1、 c2,n個集裝箱,重量是wi (i=1…n),且所有集裝箱的總重量不超過c1+c2。確定是否有可能將所有集裝箱全部裝入兩艘船。

輸入
多個測例,每個測例的輸入佔兩行。第一行一次是c1、c2和n(n<=10);第二行n個整數表示wi (i=1…n)。n等於0標誌輸入結束。

輸出
對於每個測例在單獨的一行內輸出Yes或No。

輸入樣例
7 8 2
8 7
7 9 2
8 8
0 0 0

輸出樣例
Yes
No

提示
求出不超過c1的最大值max,若總重量-max < c2則能裝入到兩艘船。

#include <stdio.h>
int c1, c2, n;
int w[11];
int cw, bestw, r;
void backtack(int i)
{
    if (i > n)
    {
        if (cw > bestw)
        {
            bestw = cw;
        }
        return;
    }
    r -= w[i];
    if (cw + w[i] <= c1)
    {
        cw += w[i];
        backtack(i + 1);
        cw -= w[i];
    }
    if (cw + r > bestw)
    {
        backtack(i + 1);
    }
    r += w[i];
}
int main()
{
    while (scanf("%d%d%d", &c1, &c2, &n) != 0 && n != 0)
    {
        cw = 0, bestw = 0, r = 0;
        int i;
        for (i = 1; i <= n; i++)
        {
            scanf("%d", &w[i]);
            r += w[i];
        }
        backtack(1);
        if (r - bestw <= c2)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

2009年

1 .奶牛飛盤隊??

  • 題意:有N(1≤N≤2000)只奶牛,每隻奶牛都有一個指數R(1≤R≤100000),請你在這N頭牛中選出多於1只牛,使指數之和是一個數F的倍數。求出有多少種方式,結果mod1億
  • 錯解:0/1揹包變形,求種數
  • 正解:標準經典動歸,與有道難題火柴遊戲類似,都需要用到mod,因爲要求出組成的f的倍數,所以方程爲f[i][j]:=f[i-1][j]+f[i-1][j+l-(a[i] mod l)) mod l]);要善用mod湊餘數的思想,減少複雜度。初值要注意f[0][0]:=1;最後結果f[n][0]-1
    不會,挖坑

2.約瑟夫問題@@

約瑟夫問題是一個非常經典的題
我專門寫了篇博客,點我傳送過去

3.N皇后問題

DFS+剪枝(填表時要回溯)。
輸入N,表示N*N棋盤,輸出不同解的個數。(輸入4得2,輸入8得92)

#include <bits/stdc++.h>
using namespace std;
int cnt = 0;
void outPut(const vector<vector<char>> &b)
{
    for (int i = 0; i < b.size(); i++)
    {
        for (int j = 0; j < b.size(); j++)
        {
            cout << b[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}
void mark(int x, int y, vector<vector<char>> &b)
{
    int n = b.size();
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            b[x][j] = '+';
            b[i][y] = '+';
            if (i + j == x + y or i - j == x - y)
            {
                b[i][j] = '+';
            }
        }
    }
    b[x][y] = 'x';
    //outPut(b);
}
void dfs(int level, vector<vector<char>> &b)
{
    if (level == b.size())
    {
        //outPut(b);
        cnt++;
        return;
    }
    for (int i = 0; i < b.size(); i++)
    {
        if (b[level][i] == '.')
        {
            vector<vector<char>> tmp = b;
            mark(level, i, b);
            dfs(level + 1, b);
            b = tmp;
            //outPut(b);
        }
    }
}
int main()
{
    int N;
    cin >> N;
    vector<vector<char>> b(N, vector<char>(N, '.')); //棋盤
    dfs(0, b);
    cout << cnt << endl;
    system("pause");
}

下面兩題不做:

  • 給4個座標判正方形:先找出兩橫看是否平行,再找出兩豎看是否平行,如此就判斷完是不是四邊形。再計算邊長是否相等即可
  • 合併有序數組:可以把兩個數組直接放在一個數組裏排序,或者雙指針,按序插入新數組

4.求圖像的周長DFS@@

我突然找到一個網站。。可以刷nwpu的題,可能是acm隊的

我一開始做錯了,後來發現X周圍非X的點代表着一單位的長度不需要額外記錄,就做出來了。debug花了好久,主要是int n = b.size(); int m = b[0].size();把mn搞混了,然後走方向時候手寫8個方向而不是for循環,寫錯了一個導致全錯。走方向如果不用for循環,發生錯誤的概論是for循環的8倍。
最後感覺腦子不靈活,可能做了一天了,腦子有點懶。

#include <bits/stdc++.h>
using namespace std;
int sum;
int count(int x, int y, vector<vector<char>> &b)
{
    int cnt = 0;
    int n = b.size();
    int m = b[0].size();
    if (x - 1 < 0)
        cnt++;
    if (x + 1 >= n)
        cnt++;
    if (y - 1 < 0)
        cnt++;
    if (y + 1 >= m)
        cnt++;
    if (x - 1 >= 0 and b[x - 1][y] == '.')
        cnt++;
    if (x + 1 < n and b[x + 1][y] == '.')
        cnt++;
    if (y - 1 >= 0 and b[x][y - 1] == '.')
        cnt++;
    if (y + 1 < m and b[x][y + 1] == '.')
        cnt++;
    return cnt;
}
bool isValid(int x, int y, vector<vector<char>> &b, vector<vector<bool>> &mp)
{
    int m = b.size();
    int n = b[0].size();
    if (x < m and x >= 0 and y < n and y >= 0 and b[x][y] == 'X' and mp[x][y] == 0)
        return 1;
    return 0;
}
void dfs(int x, int y, vector<vector<char>> &b, vector<vector<bool>> &mp)
{
    mp[x][y] = 1;
    sum += count(x, y, b);
    for (int i = -1; i <= 1; i++)
    {
        for (int j = -1; j <= 1; j++)
        {
            if (i == 0 and j == 0)
                continue;
            int xx = x + i;
            int yy = y + j;
            if (isValid(xx, yy, b, mp))
            {
                dfs(xx, yy, b, mp);
            }
        }
    }
}
int main()
{
    while (1)
    {
        int m, n, x, y;
        cin >> m >> n >> x >> y;
        if (m == 0 and n == 0 and x == 0 and y == 0)
            break;
        cin.get(); //喫y後面那個空格 不然s輸不進去
        vector<vector<char>> b(m, vector<char>(n, '?'));
        vector<vector<bool>> mp(m, vector<bool>(n, 0));
        for (int i = 0; i < m; i++)
        {
            string s;
            getline(cin, s, ' ');
            for (int j = 0; j < n; j++)
            {
                b[i][j] = s[j];
            }
        }
        dfs(x - 1, y - 1, b, mp);
        cout << sum << endl;
        sum = 0;
    }
    system("pause");
}

測試用例2 2 2 2 XX XX 2 2 2 1 .X X. 6 4 2 3 .XXX .XXX .XXX ...X ..X. X... 0 0 0 0
在這裏插入圖片描述

2008年

1.越野跑

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int time = 0;
    int M, T, U, F, D;
    cin >> M >> T >> U >> F >> D;
    int duan = 0;
    for (int i = 0; i < T; i++)
    {
        char c;
        cin >> c;
        switch (c)
        {
        case 'u':
        case 'd':
            time += (U + D);
            break;
        case 'f':
            time += (2 * F);
            break;
        default:
            break;
        }
        if (time > M)
        {
            duan = i;
            break;
        }
    }
    cout << duan << endl;
    system("pause");
}

2.環形石子合併DP

1、問題描述:問題來源 NWPU noj 1148

在一個圓形操場的四周擺放着n堆石子(n<= 100),現要將石子有次序地合併成一堆。規定每次只能選取相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記爲該次合併的得分。編一程序,讀入石子堆數n及每堆的石子數(<=20)。選擇一種合併石子的方案,使得做n-1次合併,得分的總和最小; 比如有4堆石子:44 5 9 則最佳合併方案如下:
4 4 5 9 score: 0
8 5 9 score: 8
13 9 score: 8 + 13 = 21
22 score: 8 + 13 + 22 = 43

2、輸入

可能有多組測試數據。 當輸入n=0時結束! 第一行爲石子堆數n(1<=n<=100);第二行爲n堆的石子每堆的石子數,每兩個數之間用一個空格分隔。

3、輸出

合併的最小得分,每個結果一行。

4、問題解析
這個問題和直線型的區別在於最後一堆和第一堆也是相鄰的,可以把圓形轉換成直線型,把問題擴展爲2n-1堆石子,舉個例子,如果環形石子堆是4 4 5 9,那麼轉換成直線型就變成了 4 4 5 9 4 4 5,所以最終就不是計算 0~n-1了,而是在 0n-1,1-n,2-n+1,…,n-12n-2中選擇最小的。計算方法和直線型的相同。
在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
int sum(int i, int j, vector<int> b)
{
    int ret = 0;
    for (int t = i; t <= j; t++)
    {
        ret += b[t];
    }
    return ret;
}
int fun(vector<int> &b)
{
    int ret = INT8_MAX;
    int size = b.size();
    int size0 = (size + 1) / 2;
    vector<vector<int>> dp(size, vector<int>(size, 0));
    for (int s = 1; s < size0; s++) //step步數差異
    {
        for (int i = 0; i < size - 1; i++)
        {
            for (int j = i + 1; j < size; j++)
            {
                if (j - i == s)
                {
                    if (s == 1)
                        dp[i][j] = b[i] + b[j];
                    else
                    {
                        int min = INT8_MAX;
                        for (int step = i; step < j; step++)
                        {
                            int tmp = dp[i][step] + dp[step + 1][j];
                            tmp < min ? min = tmp : NULL;
                        }
                        dp[i][j] = min + sum(i, j, b);
                    }
                    if (s == size0 - 1)
                    {
                        ret > dp[i][j] ? ret = dp[i][j] : NULL;
                    }
                }
            }
        }
    }
    return ret;
}
int main()
{
    while (1)
    {
        int n;
        cin >> n;
        if (n == 0)
            break;
        vector<int> b(0);
        for (int i = 0; i < n; i++)
        {
            int num;
            cin >> num;
            b.push_back(num);
        }
        //擴充數組b
        int size0 = b.size();
        for (int i = 0; i < size0 - 1; i++)
        {
            b.push_back(b[i]);
        }
        cout << fun(b) << endl;
    }

    system("pause");
}

與其他人的答案對比過,輸出一樣,程序正確。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章