西工大计算机考研机试题练习(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");
}

与其他人的答案对比过,输出一样,程序正确。

猜你喜欢

转载自blog.csdn.net/Protocols7/article/details/104157183