(一)动态规划问题
【题目描述】
有一个包含正数和负数的二维数组。一个子矩阵是指在该二维数据里,任意相邻的下标是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
- #include
- #include
- #include
- using namespace std;
- //f 是求一维数组最大子数组和的函数
- //g 是求二维矩阵最大子矩阵和的函数
- //a 是输入的二维矩阵
- //n 是矩阵的大小
- //l 和 r 分别是左边界和右边界
- //t 是累加和的一维数组
- //m 是当前最大的子数组和或子矩阵和
- //c 是当前累加的子数组和
- int f(vector<int>& a) {
- int m = INT_MIN, c = 0;
- for (int x : a) {
- c = max(x, c + x);//对于每个元素,计算在当前位置结束的最大子数组和
- m = max(m, c);//更新全局最大子数组和
- }
- return m;
- }
- int g(vector
int >>& a) { - int n = a.size();
- int m = INT_MIN;
-
- for (int l = 0; l < n; ++l) {
- vector<int> t(n, 0);
-
- for (int r = l; r < n; ++r) {
- for (int i = 0; i < n; ++i) {
- t[i] += a[r][i];
- }
- int c = f(t);
- m = max(m, c);
- }
- }
- return m;
- }
- int main() {
- int n;
- cin >> n;
- vector
int>> a(n, vector<int>(n)); - for (int i = 0; i < n; ++i) {
- for (int j = 0; j < n; ++j) {
- cin >> a[i][j];
- }
- }
- cout << g(a) << endl;
- return 0;
- }
(二)回溯法
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。例如,给出n = 3,生成结果为:["((()))", "(()())", "(())()", "()(())", "()()()"]。
- #include
- #include
- #include
-
- using namespace std;
- //O是已使用的左括号的数量
- //p是已使用的右括号的数量
- //r是结果
- void backtrack(vector
&r, string &c, int o, int p, int m) { - if (c.size() == m * 2) {
- r.push_back(c);
- return;
- }
- if (o < m) {
- c.push_back('(');
- backtrack(r, c, o + 1, p, m);
- c.pop_back();
- }
- if (p < o) {
- c.push_back(')');
- backtrack(r, c, o, p + 1, m);
- c.pop_back();
- }
- }
- vector
g(int n) { - vector
r; - string c;
- backtrack(r, c, 0, 0, n);
- return r;
- }
- int main() {
- int n;
- cin >> n;
- vector
r = g(n); - for (const string &s : r) {
- cout << s << endl;
- }
- return 0;
- }
(三)分支限界法
问题描述:
小易总是感到饥饿,所以作为章鱼的小易需要经常出去找贝壳吃。最开始,小易在一个初始位置x0.对于小易所处的当时位置x,它智能通过神秘的力量移动4 * x + 3或者8 * x +7。因为使用神秘力量要消耗太多体力,所以它最多只能使用神秘力量100000次。贝壳总生长在能被1000000007整除的位置(比如位置0、位置1000000007、位置2000000014等)。小易需要你帮忙计算最少使用多少次神秘力量就能吃到贝壳。
输入描述:
输入一个初始位置x0,范围为1-1000000006
输出描述:
输出小易最少需要使用神秘力量的次数,如果次数使用完还没找到贝壳,则输出-1.
输入样例
125000000
输出样例
1
- #include
- #include
- #include
- using namespace std;
-
- #define MOD 1000000007L
- #define MAX 100000
- //vist记录每个位置及其到起始位置的距离或使用力量次数
- int main(){
-
- map<long,int> vist;
- long x;//存储初始位置
-
- while (cin>>x) {
-
- queue<long> q;
- q.push(x);
- vist[x]=1;
- long xx=1;
-
- while (q.size()) {
-
- x = q.front();
- q.pop();
-
- if (x==0)//找到贝壳
- break;
-
- if (vist[x] > MAX)
- continue;
-
- xx = ((x<<2)+3) % MOD;
-
- if (vist.find(xx) == vist.end())//新位置未被访问过
- {
- q.push(xx);
- vist[xx] = vist[x]+1;
- }
-
- xx = ((x<<3)+7) % MOD;
-
- if (vist.find(xx) == vist.end()){
- q.push(xx);
- vist[xx] = vist[x]+1;
- }
- }
- cout<<(q.size() ? vist[x]-1 : -1)<
- }
-
- return 0;
- }
(四)网络流问题
流水问题
现在有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 //最大流水量
- #include
- #include
- #include
- #include
- using namespace std;
- //a代表邻接表
- //e代表边
- //adEdge代表添加边
- //mF代表最大流函数
- //f是累计的最大流量
- const int INF = 1e9;
- //f是边的起点
- //t是边的终点
- //c是边的容量
- //f1是边的流量
- struct Edge {
- int f, t, c, fl;
- };
- vector
int>> a; - vector
e; - void adEdge(int f, int t, int c) {
- Edge e1 = {f, t, c, 0};
- Edge e2 = {t, f, c, 0};
- a[f].push_back(e.size());
- e.push_back(e1);
- a[t].push_back(e.size());
- e.push_back(e2);
- }
- //s是源点,k是汇点
- //p数组用来记录路径
- int mF(int s, int k) {
- int f = 0;
- while (true) {
- vector<int> p(a.size(), -1);
- queue<int> q;
- q.push(s);
- p[s] = s;//源点已被访问
- while (!q.empty() && p[k] == -1) {
- int u = q.front();
- q.pop();
- for (int i : a[u]) {
- Edge &x = e[i];
- if (p[x.t] == -1 && x.c - x.fl > 0) {
- q.push(x.t);
- p[x.t] = i;
- }
- }
- }
- if (p[k] == -1) break;
- int cF = INF;//表示路径上最小的剩余容量
- for (int u = k; u != s; u = e[p[u]].f) {
- cF = min(cF, e[p[u]].c - e[p[u]].fl);
- }
- for (int u = k; u != s; u = e[p[u]].f) {
- e[p[u]].fl += cF;//将路径上正向边的流量增加cF
- e[p[u]^1].fl -= cF;//将路径上反向边的流量减少cF
- }
- f += cF;
- }
- return f;
- }
-
- int main() {
- int m, n;
- cin >> m >> n;
- a.resize(m + 1);
- for (int i = 0; i < n; ++i) {
- int f, t, c;
- cin >> f >> t >> c;
- adEdge(f, t, c);
- }
- int s = 1, k = m;
- int mf = mF(s, k);
- cout << mf << endl;
-
- return 0;
- }