2021算法笔记Codeup、pat刷题记录
next_permutation
永远的神
#include
#include
#include
using namespace std;
int main() {
int n;
vector<int> vi;
scanf("%d", &n);
for (int i = 1;i <= n;++i) {
vi.push_back(i);
}
do {
for (int i = 0;i < vi.size();++i) {
if (i != 0) printf(" ");
printf("%d", vi[i]);
}
printf("\n");
} while (next_permutation(vi.begin(), vi.end()));
return 0;
}
递归写法,不难但是小错误又找了很久错。。
#include
#include
using namespace std;
int n;
vector<int> vi;
bool hashTable[15] = { false };//判断数字是否使用过
void get_ans(int index) {
if (index == n + 1) {
for (int i = 0;i < vi.size();++i) {
if (i != 0) printf(" ");
printf("%d", vi[i]);
}
printf("\n");
return;
}
else {
for (int i = 1;i <= n;++i) {
if (hashTable[i] == false) {
vi.push_back(i);
hashTable[i] = true;
get_ans(index + 1);//这里index+1
hashTable[i] = false;
vi.pop_back();
}
}
}
}
int main() {
scanf("%d", &n);
get_ans(1);
return 0;
}
题目里要求我们不用递归的方式做这题,暂时还在思考做法。回头看看数据结构书可能会有些思路
#include
#include
using namespace std;
const int maxn = 25;
bool hashTable[maxn] = { false };
int n, r;
vector<int> vi;
void get_ans(int index, int cnt) {//index表示下一位数的起始,cnt为数的位数
if (cnt == r + 1) {//数为4时输出
for (int i = 0;i < vi.size();++i) {
if (i != 0) printf(" ");
printf("%d", vi[i]);
}
printf("\n");
}
else {
for (int i = index;i <= n;++i) {
if (hashTable[i] == false) {
hashTable[i] = true;
vi.push_back(i);
get_ans(i + 1, cnt + 1);//将i+1放入进行递归
vi.pop_back();
hashTable[i] = false;
}
}
}
}
int main() {
scanf("%d %d", &n, &r);
get_ans(1, 1);
return 0;
}
又有很多小错误,谢特
#include
#include
#include
using namespace std;
const int maxn = 20;
vector<int> num, vi;
int n, r, cnt = 0;
bool is_Prime(int x) {
int sqr = sqrt(1.0 * x);
for (int i = 2;i <= sqr;++i) {
if (x % i == 0) return false;
}
return true;
}
void DFS(int index, int sum, int count) {
if (count == r) {
if (is_Prime(sum)) {
++cnt;
return;
}
}
if (index == n) return;
vi.push_back(num[index]);
DFS(index + 1, sum + num[index], count + 1);
vi.pop_back();
DFS(index + 1, sum, count);
}
int main() {
scanf("%d %d", &n, &r);
for (int i = 0;i < n;++i) {
int temp;
scanf("%d", &temp);
num.push_back(temp);
}
DFS(0, 0, 0);
printf("%d\n", cnt);
return 0;
}
#include
#include
using namespace std;
const int maxn = 15;
int n, cnt = 0, P[maxn];
int hashTable[maxn] = { false };
void N_queen(int index) {
if (index == n + 1) {
++cnt;
for (int i = 1;i <= n;++i) {
if (i != 1) printf(" ");
printf("%d", P[i]);
}
printf("\n");
return;
}
for (int i = 1;i <= n;++i) {
if (hashTable[i] == false) {
bool flag = true;
for (int j = 1;j < index;++j) {//剪枝
if (abs(index - j) == abs(P[j] - i)) {
flag = false;
break;
}
}
if (flag) {
hashTable[i] = true;
P[index] = i;
N_queen(index + 1);
hashTable[i] = false;
}
}
}
}
int main() {
scanf("%d", &n);
N_queen(1);
if (!cnt) printf("no solute!\n");
return 0;
}
来自大佬的数据结构中出栈序列的个数算法
原理解释:
卡特兰数的一个代表例子f(5)=42
出栈方式数量的题可以这么理解:
设n个数出栈方式数量为f(n)
因为入栈的顺序是确定的,下标记为1,2,3…n
设最后一个出栈的是第k个数,则说明k之前的k-1个数先完成进栈,有f(k-1)种方式
然后k之后的n-k个数再完成进栈出栈,有f(n-k)种方式
最后第k个数出栈,这时就有f(k-1)*f(n-k)种方式
而每个数都有可能是最后出栈的
所以有
f(n)=f(0)*f(n-1)+f(1)*f(n-2)+…+f(k-1)*f(n-k)+…+f(n-1)*f(0)
上面f(0)=1是为了写成统一式:
由上式的通项就是卡特兰数f(n)=C(n,2n)/n+1
于是有如下代码,但是这个数增长的很快,如果需要可以计算n为很大时的序列个数时,可以自定义大数计算卡特兰数。
#include
using namespace std;
int DFS(int index) {
if (index == 0 || index == 1) return 1;
int temp = 0;
for (int i = 1;i <= index;++i) {
temp += DFS(i - 1) * DFS(index - i);
}
return temp;
}
int main() {
int n;
scanf("%d", &n);
printf("%d", DFS(n));
return 0;
}
题目里只需要计算能输出的序列统计,因此并不需要实际的申请一个栈,我的思路是使用递归 DFS(int push,int pop),递归边界为push==n
(即已经全部进栈了,接下来只能一个个出栈),pop==n
(即所有元素均已出栈);接下来递归即为,当执行到某一步时,我可以选择出栈i个元素(0<=i<=push-pop)后进栈一个元素。
#include
int n, cnt = 0;
void DFS(int push, int pop) {
if (pop == n || push == n) {
++cnt;
return;
}
int i = 0;
while (pop + i <= push) {
DFS(push + 1, pop + i);
++i;
}
}
int main() {
scanf("%d", &n);
DFS(0, 0);
printf("%d", cnt);
return 0;
}
写题10分钟改错2小时- -,递归里面的y+1<=m
写成了y+1<=n
结果改了半个多小时的错,自己测试方阵可以出结果,试了几个ncnt==0
,即没有路径的话,需要输出-1;
#include
struct point {
int x, y;
}start, end, path[250];
bool map[17][17] = { 0 }, hashTable[17][17] = { 0 };
int n, m, cnt = 0;
void print(int foot) {
for (int i = 0;i <= foot;++i) {
if (i != 0) printf("->");
printf("(%d,%d)", path[i].x, path[i].y);
}
printf("\n");
}
void DFS(int x, int y, int foot) {
if (x == end.x && y == end.y) {
++cnt;
path[foot].x = x, path[foot].y = y;
print(foot);
return;
}
if (map[x][y] == 0 || hashTable[x][y] == true) return;
path[foot].x = x, path[foot].y = y;
hashTable[x][y] = true;
if (y - 1 > 0) DFS(x, y - 1, foot + 1);
if (x - 1 > 0) DFS(x - 1, y, foot + 1);
if (y + 1 <= m) DFS(x, y + 1, foot + 1);
if (x + 1 <= n) DFS(x + 1, y, foot + 1);
hashTable[x][y] = false;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1;i <= n;++i) {
for (int j = 1;j <= m;++j) {
scanf("%d", &map[i][j]);
}
}
scanf("%d%d%d%d", &start.x, &start.y, &end.x, &end.y);
DFS(start.x, start.y, 0);
if (cnt == 0) printf("-1\n");
return 0;
}
最开始照着题目意思写的,超时了很多
要想不超时,最重要的就是预处理n^p
,将所有不超过N的n^p
存入vector
中,在递归的每一步中都记录sum和facSum值,不要等到最后才遍历数组计算两个值。
#include
#include
#include
using namespace std;
int n, k, p, maxFacSum = -1;
vector<int> fac, temp, ans;
int power(int x) {
int ans = 1;
for (int i = 0;i < p;++i) {
ans *= x;
}
return ans;
}
void init() {
int temp = 0;
for (int i = 1;temp <= n;++i) {
fac.push_back(temp);
temp = power(i);
}
}
void DFS(int index, int nowK, int sum, int facSum) {
if (sum == n && nowK == k) {
if (facSum > maxFacSum) {
maxFacSum = facSum;
ans = temp;
}
return;
}
if (sum > n || nowK > k) return;
if (index - 1 >= 0) {
temp.push_back(index);
DFS(index, nowK + 1, sum + fac[index], facSum + index);
temp.pop_back();
DFS(index - 1, nowK, sum, facSum);
}
}
int main() {
scanf("%d %d %d", &n, &k, &p);
init();
DFS(fac.size() - 1, 0, 0, 0);
if (maxFacSum == -1) printf("Impossible\n");
else {
printf("%d = ", n);
for (int i = 0;i < ans.size();++i) {
if (i != 0) printf(" + ");
printf("%d^%d", ans[i], p);
}
}
return 0;
}
DFS写法
#include
using namespace std;
const int maxn = 100;
struct Node {
int x, y;
}node;
int n, m;
int matrix[maxn][maxn];
bool inq[maxn][maxn] = { false };
int X[4] = { 0,-1,0,1 };//增量数组
int Y[4] = { -1,0,1,0 };
bool judge(int x, int y) {//判断坐标(x,y)是否需要访问
if (x < 0 || y < 0 || x >= n || y >= m) return false;//越界则返回false
if (inq[x][y] == true || matrix[x][y] == 0) return false;//已入队过或当前位置为0返回false
return true;//否则
}
void DFS(int x, int y) {//DFS函数访问位置(x,y)所在的块,将该块中所有的"1"的inq都设置成true;
if (judge(x, y)) {
inq[x][y] = true;
for (int i = 0;i < 4;++i) {
DFS(x + X[i], y + Y[i]);
}
}
}
int main() {
scanf("%d %d", &n, &m);
for (int x = 0;x < n;++x) {
for (int y = 0;y < m;++y) {
scanf("%d", &matrix[x][y]);
}
}
int ans = 0;
for (int x = 0;x < n;++x) {
for (int y = 0;y < m;++y) {
if (matrix[x][y] == 1 && inq[x][y] == false) {
++ans;
DFS(x, y);
}
}
}
printf("%d\n", ans);
return 0;
}
BFS的代码
void BFS(int x,int y){
queue<Node> qu;
inq[x][y]=true;
node.x=x,node.y=y;
qu.push(node);
while(!qu.empty()){
Node top=qu.front();
qu.pop();
for(int i=0;i<4;++i){
int newx=top.x+X[i];
int newy=top.y+Y[i];
if(judge(newx,newy)){
node.x=newx,node.y=newy;//node与qi.front无关
qu.push(node);
inq[newx][newy]=true;
}
}
}
}
#include
#include
#include
using namespace std;
const int maxn = 100;
struct Node {
int x, y;
int step;
}S, T, node;
int n, m;
char maze[maxn][maxn];
bool inq[maxn][maxn] = { false };
int X[4] = { 0,0,1,-1 };
int Y[4] = { 1,-1,0,0 };
bool judge(int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m) return false;
if (maze[x][y] == '*' || inq[x][y] == true) return false;
return true;
}
int BFS() {
queue<Node> qu;
qu.push(S);
while (!qu.empty()) {
Node top = qu.front();
qu.pop();
if (top.x == T.x && top.y == T.y) {
return top.step;
}
for (int i = 0;i < 4;++i) {
int newX = top.x + X[i];
int newY = top.y + Y[i];
if (judge(newX, newY)) {
node.x = newX, node.y = newY;
node.step = top.step + 1;
qu.push(node);
inq[newX][newY] = true;
}
}
}
return -1;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 0;i < n;++i) {
getchar();
for (int j = 0;j < m;++j) {
maze[i][j] = getchar();
}
maze[i][m + 1] = '\0';
}
scanf("%d%d%d%d", &S.x, &S.y, &T.x, &T.y);
S.step = 0;
printf("%d\n", BFS());
return 0;
}
改错改到半夜- -,吐了
内存 108916KB 耗时665ms,感觉写的应该不行。
#include
#include
using namespace std;
const int maxn = 8;
struct Node {
int x, y;
int step;
}node, S, T;
char matrix[maxn][maxn];
int X[9] = { 0,-1,0,1,-1,-1,1,1,0 };
int Y[9] = { -1,0,1,0,-1,1,-1,1,0 };
bool judge(int x, int y, int step) {
if (x < 0 || x >= maxn || y < 0 || y >= maxn) return false;
if (x - step >= 0) if (matrix[x - step][y] == 'S') return false;
return true;
}
bool BFS() {
queue<Node> qu;
qu.push(S);
while (!qu.empty()) {
Node top = qu.front();
qu.pop();
if (top.x == 7 && top.y == 7) return true;
for (int i = 0;i < 9;++i) {
int newX = top.x + X[i];
int newY = top.y + Y[i];
if (judge(newX, newY, top.step) && judge(newX, newY, top.step + 1)) {
node.x = newX, node.y = newY, node.step = top.step + 1;
qu.push(node);
}
}
}
return false;
}
int main() {
int n;
S.x = 7, S.y = 0, S.step = 0;
T.x = 0, T.y = 7;
scanf("%d", &n);
for (int k = 1;k <= n;++k) {
for (int i = 0;i < maxn;++i) {
getchar();
scanf("%s", &matrix[i]);
}
if (BFS()) printf("Case #%d: Yes\n", k);
else printf("Case #%d: No\n", k);
}
return 0;
}
根据下面一道题发现了这题的问题在于走回头路以及对于BFS退出时判断的位置,修改后
内存占用 10244KB
耗时 64ms
相比于只修改不走回头路
内存 65024KB
耗时 461ms
#include
#include
using namespace std;
const int maxn = 8;
struct Node {
int x, y;
int step;
int lastx, lasty;
}node, S, T;
char matrix[maxn][maxn];
int X[9] = { 0,-1,0,1,-1,-1,1,1,0 };
int Y[9] = { -1,0,1,0,-1,1,-1,1,0 };
bool judge(int x, int y, int step) {
if (x < 0 || x >= maxn || y < 0 || y >= maxn) return false;
if (x - step >= 0) if (matrix[x - step][y] == 'S') return false;
return true;
}
bool BFS() {
queue<Node> qu;
qu.push(S);
while (!qu.empty()) {
Node top = qu.front();
qu.pop();
for (int i = 0;i < 9;++i) {
int newX = top.x + X[i];
int newY = top.y + Y[i];
if (judge(newX, newY, top.step) && judge(newX, newY, top.step + 1) && (newX != top.lastx || newY != top.lasty)) {
node.x = newX, node.y = newY, node.step = top.step + 1;
node.lastx = top.x, node.lasty = top.y;
if (node.x == 7 && node.y == 7) return true;//将上面的代码写在这可以省去很多入队列的时间!!!
qu.push(node);
}
}
}
return false;
}
int main() {
int n;
S.x = 7, S.y = 0, S.step = 0, S.lastx = -1, S.lasty = -1;
T.x = 0, T.y = 7;
scanf("%d", &n);
for (int k = 1;k <= n;++k) {
for (int i = 0;i < maxn;++i) {
getchar();
scanf("%s", &matrix[i]);
}
if (BFS()) printf("Case #%d: Yes\n", k);
else printf("Case #%d: No\n", k);
}
return 0;
}
以后看到内存超限就要想到回头路的问题!!!
提交了n遍,就为了找出错误,原来是lastx,lasty必须要放在结构体里,不然会导致无限循环操作。想明白了
内存 2400KB
耗时 5ms
#include
#include
using namespace std;
struct matrix {
int m[3][3];
int x0, y0;//记录0点位置
int step;
int lastx, lasty;
}node, S, T;
bool judge(int x, int y) {
if (x < 0 || y < 0 || x >= 3 || y >= 3) return false;
return true;
}
bool same(int m[3][3]) {
for (int i = 0;i < 3;++i) {
for (int j = 0;j < 3;++j) {
if (m[i][j] != T.m[i][j]) return false;
}
}
return true;
}
int X[4] = { 0,0,-1,1 };
int Y[4] = { -1,1,0,0 };
//int lastx=-1,lasty=-1;
int BFS() {
queue<matrix> qu;
qu.push(S);
while (!qu.empty()) {
matrix top = qu.front();
qu.pop();
for (int i = 0;i < 4;++i) {
int newx0 = top.x0 + X[i], newy0 = top.y0 + Y[i];
if (judge(newx0, newy0) && (newx0 != top.lastx || newy0 != top.lasty)) {//防止无限循环
node.x0 = newx0, node.y0 = newy0;
node.step = top.step + 1;
node.lastx = top.x0, node.lasty = top.y0;
// lastx=top.x0,lasty=top.y0; 错误原因,导致无限循环,要将上一步绑定到结点
for (int j = 0;j < 3;++j) {
for (int k = 0;k < 3;++k) {
node.m[j][k] = top.m[j][k];
}
}
node.m[top.x0][top.y0] = node.m[newx0][newy0];
node.m[newx0][newy0] = 0;
if (same(node.m)) {
return node.step;
}
qu.push(node);
}
}
}
return -1;
}
int main() {
for (int i = 0;i < 3;++i) {
for (int j = 0;j < 3;++j) {
scanf("%d", &S.m[i][j]);
if (S.m[i][j] == 0) {
S.x0 = i;
S.y0 = j;
}
}
}
S.step = 1, S.lastx = -1, S.lasty = -1;
for (int i = 0;i < 3;++i) {
for (int j = 0;j < 3;++j) {
scanf("%d", &T.m[i][j]);
}
}
printf("%d\n", BFS());
return 0;
}
这题不难,但是真坑,
坑一:是求由基本状态转换为目标状态(给出的状态)的最小步数,而不是由目标状态(给出的状态)转换为基本状态的最小步数。
坑二:题目输出的序列转换但二维数组中并不是按常规方法转换的。
1 2 3 4 5 6 7 8
->
1 2 3 4
8 7 6 5
用map判重,不然会超时,这里map的使用也很有讲究,要将矩阵转换成数字,最终内存耗时:
内存:9508KB
耗时:134ms
#include
#include
#include
#include
#include
using namespace std;
const char op[3] = { 'A','B','C' };
struct Node {
int b[2][4];
vector<int> v;
int last;
int step;
}node, S, T;
map<int, bool> mp;
void change(int x, Node& node) {//操作
if (x == 0) {//'A'
for (int i = 0;i < 4;++i) {
swap(node.b[0][i], node.b[1][i]);//上下对换
}
}
else if (x == 1) {//'B'
for (int i = 0;i < 2;++i) {
reverse(node.b[i], node.b[i] + 3);//倒置左边三个
reverse(node.b[i], node.b[i] + 4);//倒置所有,效果——
}
}
else {//'C'
int temp = node.b[0][1];
node.b[0][1] = node.b[1][1];
node.b[1][1] = node.b[1][2];
node.b[1][2] = node.b[0][2];
node.b[0][2] = temp;//不知道有没有更好的写法
}
}
bool same(Node node) {
for (int j = 0;j < 2;++j) {
for (int k = 0;k < 4;++k) {
if (node.b[j][k] != T.b[j][k]) return false;
}
}
return true;
}
void BFS() {
queue<Node> qu;
qu.push(S);
while (!qu.empty()) {
Node top = qu.front();
qu.pop();
int temp = 0;
if (same(top)) return;
for (int i = 0;i < 3;++i) {
if (top.last == 0 && i == 0) continue;//防止倒转两次
node = top;
change(i, node);
for (int i = 0;i < 2;++i) {
for (int j = 0;j < 4;++j) {
temp = temp * 10 + top.b[i][j];
}
}
if (mp[temp] == true) continue;//判重
else mp[temp] = true;
node.v = top.v;
node.v.push_back(i);
node.last = i;
node.step = top.step + 1;
if (same(node)) return;
qu.push(node);
node.v.clear();
}
}
}
int main() {
while (scanf("%d", &T.b[0][0]) != EOF) {
for (int i = 1;i <= 4;++i) {//1 2 3 4 8 7 6 5
S.b[0][i - 1] = i;
S.b[1][i - 1] = 9 - i;
}
for (int i = 1;i < 4;++i) scanf("%d", &T.b[0][i]);
for (int i = 0;i < 4;++i) scanf("%d", &T.b[1][3 - i]);
S.last = -1;
BFS();
printf("%d\n", node.step);
for (int i = 0;i < node.v.size();++i) {
printf("%c", op[node.v[i]]);
}
printf("\n");
}
return 0;
}
在这里插入代码片
阿西吧,赋值写成==,代码没错,愣是多几个值,粗心要命
题目不难照着书上思路写就好。
#include
#include
using namespace std;
struct Node {
int x, y, z;
}node;
int m, n, l, t;
int X[6] = { 0,0,0,0,1,-1 };
int Y[6] = { 0,0,-1,1,0,0 };
int Z[6] = { -1,1,0,0,0,0 };//增量数组
int pixel[1290][130][61];
bool inq[1290][130][61] = { false };
bool judge(int x, int y, int z) {
if (x < 0 || y < 0 || z < 0 || x >= m || y >= n || z >= l) return false;
if (pixel[x][y][z] == 0 || inq[x][y][z] == true) return false;
return true;
}
int BFS(int x, int y, int z) {
int count = 0;
node.x = x, node.y = y, node.z = z;
queue<Node> qu;
qu.push(node);
inq[x][y][z] = true;
while (!qu.empty()) {
Node top = qu.front();
qu.pop();
++count;
for (int i = 0;i < 6;++i) {
int newx = top.x + X[i];
int newy = top.y + Y[i];
int newz = top.z + Z[i];
if (judge(newx, newy, newz)) {
inq[newx][newy][newz] = true;
node.x = newx, node.y = newy, node.z = newz;
qu.push(node);
}
}
}
if (count >= t) return count;
else return 0;
}
int main() {
scanf("%d %d %d %d", &m, &n, &l, &t);
for (int k = 0;k < l;++k) {
for (int i = 0;i < m;++i) {
for (int j = 0;j < n;++j) {
scanf("%d", &pixel[i][j][k]);
}
}
}
int cnt = 0;
for (int k = 0;k < l;++k) {
for (int i = 0;i < m;++i) {
for (int j = 0;j < n;++j) {
if (inq[i][j][k] == false && pixel[i][j][k] == 1) {
cnt += BFS(i, j, k);
}
}
}
}
printf("%d\n", cnt);
return 0;
}