• NEFU算法设计与分析课程设计


    (一)动态规划问题

    最大子矩阵问题

    【题目描述】

    有一个包含正数和负数的二维数组。一个子矩阵是指在该二维数据里,任意相邻的下标是1 * 1或更大的子数组。一个子矩阵的和是指该子矩阵中所有元素的和。本题中,把具有最大和的子矩阵称为最大子矩阵。

    例如,如下数组的最大子矩阵位于左下角,其和为15。

    0

    -2

    -7

    0

    9

    2

    -6

    2

    -4

    1

    -4

    1

    -1

    8

    0

    -2

    【输入】

    是N * N个整数的数组。第一行是一个正整数N,表示二维方阵的大小。接下来是N2个整数(空格和换行隔开)。该数组的N2个整数,是以行序给出的。也就是,显示第一行的数,由左到右;然后是第二行的数,由左到右,等等。

    N可能达到100,数组元素的范围是[-127,127]

    【输出】

    最大子矩阵的和。

    【输入样例】

    4

     0 -2 -7 0 9 2 -6 2

    -4 1 -4  1 -1 8 0 -2

    【输出样例】

    15

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //f 是求一维数组最大子数组和的函数
    6. //g 是求二维矩阵最大子矩阵和的函数
    7. //a 是输入的二维矩阵
    8. //n 是矩阵的大小
    9. //l 和 r 分别是左边界和右边界
    10. //t 是累加和的一维数组
    11. //m 是当前最大的子数组和或子矩阵和
    12. //c 是当前累加的子数组和
    13. int f(vector<int>& a) {
    14. int m = INT_MIN, c = 0;
    15. for (int x : a) {
    16. c = max(x, c + x);//对于每个元素,计算在当前位置结束的最大子数组和
    17. m = max(m, c);//更新全局最大子数组和
    18. }
    19. return m;
    20. }
    21. int g(vectorint>>& a) {
    22. int n = a.size();
    23. int m = INT_MIN;
    24. for (int l = 0; l < n; ++l) {
    25. vector<int> t(n, 0);
    26. for (int r = l; r < n; ++r) {
    27. for (int i = 0; i < n; ++i) {
    28. t[i] += a[r][i];
    29. }
    30. int c = f(t);
    31. m = max(m, c);
    32. }
    33. }
    34. return m;
    35. }
    36. int main() {
    37. int n;
    38. cin >> n;
    39. vectorint>> a(n, vector<int>(n));
    40. for (int i = 0; i < n; ++i) {
    41. for (int j = 0; j < n; ++j) {
    42. cin >> a[i][j];
    43. }
    44. }
    45. cout << g(a) << endl;
    46. return 0;
    47. }

    (二)回溯法

    括号生成问题

    给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。例如,给出n = 3,生成结果为:["((()))", "(()())", "(())()", "()(())", "()()()"]。

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //O是已使用的左括号的数量
    6. //p是已使用的右括号的数量
    7. //r是结果
    8. void backtrack(vector &r, string &c, int o, int p, int m) {
    9. if (c.size() == m * 2) {
    10. r.push_back(c);
    11. return;
    12. }
    13. if (o < m) {
    14. c.push_back('(');
    15. backtrack(r, c, o + 1, p, m);
    16. c.pop_back();
    17. }
    18. if (p < o) {
    19. c.push_back(')');
    20. backtrack(r, c, o, p + 1, m);
    21. c.pop_back();
    22. }
    23. }
    24. vector g(int n) {
    25. vector r;
    26. string c;
    27. backtrack(r, c, 0, 0, n);
    28. return r;
    29. }
    30. int main() {
    31. int n;
    32. cin >> n;
    33. vector r = g(n);
    34. for (const string &s : r) {
    35. cout << s << endl;
    36. }
    37. return 0;
    38. }

    (三)分支限界法

    求解饥饿的小易问题

    问题描述:

    小易总是感到饥饿,所以作为章鱼的小易需要经常出去找贝壳吃。最开始,小易在一个初始位置x0.对于小易所处的当时位置x,它智能通过神秘的力量移动4 * x + 3或者8 * x +7。因为使用神秘力量要消耗太多体力,所以它最多只能使用神秘力量100000次。贝壳总生长在能被1000000007整除的位置(比如位置0、位置1000000007、位置2000000014等)。小易需要你帮忙计算最少使用多少次神秘力量就能吃到贝壳。

    输入描述:

    输入一个初始位置x0,范围为1-1000000006

    输出描述:

    输出小易最少需要使用神秘力量的次数,如果次数使用完还没找到贝壳,则输出-1.

    输入样例

    125000000

    输出样例

    1

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. #define MOD 1000000007L
    6. #define MAX 100000
    7. //vist记录每个位置及其到起始位置的距离或使用力量次数
    8. int main(){
    9. map<long,int> vist;
    10. long x;//存储初始位置
    11. while (cin>>x) {
    12. queue<long> q;
    13. q.push(x);
    14. vist[x]=1;
    15. long xx=1;
    16. while (q.size()) {
    17. x = q.front();
    18. q.pop();
    19. if (x==0)//找到贝壳
    20. break;
    21. if (vist[x] > MAX)
    22. continue;
    23. xx = ((x<<2)+3) % MOD;
    24. if (vist.find(xx) == vist.end())//新位置未被访问过
    25. {
    26. q.push(xx);
    27. vist[xx] = vist[x]+1;
    28. }
    29. xx = ((x<<3)+7) % MOD;
    30. if (vist.find(xx) == vist.end()){
    31. q.push(xx);
    32. vist[xx] = vist[x]+1;
    33. }
    34. }
    35. cout<<(q.size() ? vist[x]-1 : -1)<
    36. }
    37. return 0;
    38. }

    (四)网络流问题

    流水问题

    现在有m个池塘(从1到m开始编号,1为源点,m为汇点)及n条水渠。假设已经给出这n条水渠所连接的池塘和所能流过的水量,设计算法求水渠中所能流过的水的最大容量。示例如下:

    输入:

    4  5    //池塘数m和水渠数n

    1  2   40   //所连接的池塘和所能流过的水量

    1  4   20

    2  4   20

    2  3   30

    3  4   10

    输出:50    //最大流水量

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. //a代表邻接表
    7. //e代表边
    8. //adEdge代表添加边
    9. //mF代表最大流函数
    10. //f是累计的最大流量
    11. const int INF = 1e9;
    12. //f是边的起点
    13. //t是边的终点
    14. //c是边的容量
    15. //f1是边的流量
    16. struct Edge {
    17. int f, t, c, fl;
    18. };
    19. vectorint>> a;
    20. vector e;
    21. void adEdge(int f, int t, int c) {
    22. Edge e1 = {f, t, c, 0};
    23. Edge e2 = {t, f, c, 0};
    24. a[f].push_back(e.size());
    25. e.push_back(e1);
    26. a[t].push_back(e.size());
    27. e.push_back(e2);
    28. }
    29. //s是源点,k是汇点
    30. //p数组用来记录路径
    31. int mF(int s, int k) {
    32. int f = 0;
    33. while (true) {
    34. vector<int> p(a.size(), -1);
    35. queue<int> q;
    36. q.push(s);
    37. p[s] = s;//源点已被访问
    38. while (!q.empty() && p[k] == -1) {
    39. int u = q.front();
    40. q.pop();
    41. for (int i : a[u]) {
    42. Edge &x = e[i];
    43. if (p[x.t] == -1 && x.c - x.fl > 0) {
    44. q.push(x.t);
    45. p[x.t] = i;
    46. }
    47. }
    48. }
    49. if (p[k] == -1) break;
    50. int cF = INF;//表示路径上最小的剩余容量
    51. for (int u = k; u != s; u = e[p[u]].f) {
    52. cF = min(cF, e[p[u]].c - e[p[u]].fl);
    53. }
    54. for (int u = k; u != s; u = e[p[u]].f) {
    55. e[p[u]].fl += cF;//将路径上正向边的流量增加cF
    56. e[p[u]^1].fl -= cF;//将路径上反向边的流量减少cF
    57. }
    58. f += cF;
    59. }
    60. return f;
    61. }
    62. int main() {
    63. int m, n;
    64. cin >> m >> n;
    65. a.resize(m + 1);
    66. for (int i = 0; i < n; ++i) {
    67. int f, t, c;
    68. cin >> f >> t >> c;
    69. adEdge(f, t, c);
    70. }
    71. int s = 1, k = m;
    72. int mf = mF(s, k);
    73. cout << mf << endl;
    74. return 0;
    75. }

  • 相关阅读:
    打出「智驾之王」,小鹏1024科技日为什么这么敢?
    【访谈】Eotalk Vol.02:从极客到 CEO,开发者应该如何提升技术领导力?
    LeetCode(力扣)40. 组合总和 IIPython
    was下log4j设置日志不输出问题
    我的 Kafka 旅程 - Producer
    Docker学习——⑥
    μC/OS-II---内核:多任务与调度
    折叠始祖摩托罗拉,困于“性价比”折叠屏
    ARM汇编之数据处理指令
    C语言源代码系列-管理系统之销售管理系统设计
  • 原文地址:https://blog.csdn.net/m0_73581206/article/details/139991406