双指针 和 bfs + dfs
日志统计
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
#define deb(x) cout << #x << "=" << x << endl
#define deb2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl
#define deb3(x, y, z) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << endl
#define debv(v) for(auto x:v) cout<<x<<" "
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int cnt[N];
bool st[N];
PII q[N];
int n, d, k;
int main()
{
cin >> n >> d >> k; // 不要读入反了
for(int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
sort(q, q + n);
// for(int i = 0; i < n; i ++ ) deb2(q[i].x, q[i].y);
for(int i = 0, j = 0; i < n; i ++ ) // 滑动
{
int t = q[i].y;
cnt[t] ++ ;
while(q[i].x - q[j].x >= d) cnt[q[j ++].y] -- ;
if(cnt[t] >= k) st[t] = true;
}
for(int i = 0; i <= 1e5; i ++ )
if(st[i])
cout << i << endl;
}
1113. 红与黑
不同点: 起点和终点发生变化,故在判断结尾的时候 -> 存在不用遍历完所有的点即可找到终点的特性
注: 可用dfs, 也可用bfs, dfs 对于这题可以少些一个队列, 使代码精简
错误: queue<int,int> 错误
#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second
#define deb(x) cout << #x << "=" << x << endl
#define deb2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl
#define deb3(x, y, z) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << endl
#define deb4(x, y, z, w) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << ","<< #w << "=" << w << endl
#define debv(v) for(auto x:v) cout<<x<<" "
#define gg exit(0);
using namespace std;
const int N = 20;
int n, m, cnt;
char g[N][N];
bool st[N][N];
void dfs(int sx, int sy)
{
// 初始化
st[sx][sy] = true;
cnt ++ ;
// 具象化
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
for(int i = 0; i < 4; i ++ ) // 深搜也要判断情况
{
int a = dx[i] + sx, b = dy[i] + sy;
if(a < 0 || a >= n || b < 0 || b >= m) continue;
if(st[a][b] || g[a][b] != '.') continue;
dfs(a, b);
}
}
void bfs(int sx, int sy)
{
// 初始化
queue<PII> q;
q.push({sx, sy});
st[sx][sy] = true;
// 具象化
while(q.size())
{
PII t = q.front();
q.pop();
cnt ++ ;
for(int i = 0; i < 4; i ++ )
{
int a = dx[i] + t.x, b = dy[i] + t.y;
if(a < 0 || a >= n || b < 0 || b >= m) continue;
if(st[a][b] || g[a][b] == '#') continue;
st[a][b] = true;
q.push({a, b});
}
}
}
int main()
{
while(cin >> m >> n, n || m) // emmm, 调了半个小时, 竟然是这里的错误, 呜呜
{
cnt = 0; // 记得把 cnt 初始化成 0
int a = 0, b = 0;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < m; j ++ )
{
cin >> g[i][j];
if(g[i][j] == '@')
a = i, b = j;
}
memset(st, 0, sizeof st); // 因为有多组测试数据
dfs(a, b);
cout << cnt << endl;
}
}
扩展
1096. 地牢大师
92. 递归实现指数型枚举
92. 递归实现指数型枚举
这种遍历方法是有点错误的, 下面是正解, 别人的
题解
重点: 如何选择一种遍历方式可以将所有的情况枚举到
本题, 其实对于一个数字只有选与不选的情况, 而且是递增的, 看 1 选 or 不选, 第二步, 看 2 选 or 不选, 第三步, 看 3 选 or 不选
123
1 _ u == 1
12 1 2 _ u == 2
123 12 1 13 23 2 _ 3 u == 3
// 1 _ u == 1
// 12 1 2 _ u == 2
// 123 12 1 13 23 2 _ 3 u == 3
#include <iostream>
#include <cstring>
#include <algorithm>
#define deb(x) cout << #x << "=" << x << endl
#define deb2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl
#define deb3(x, y, z) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << endl
#define deb4(x, y, z, w) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << ","<< #w << "=" << w << endl
#define debv(v) for(auto x:v) cout<<x<<" "
#define gg exit(0);
using namespace std;
const int N = 15;
bool st[N];
int n;
void dfs(int u)
{
if(u > n)
{
for(int i = 1; i <= n; i ++ )
if(st[i]) cout << i << ' ';
cout << endl;
return ; // 注意要记得 return ;
}
st[u] = true;
dfs(u + 1);
st[u] = false;
dfs(u + 1);
}
int main()
{
cin >> n;
dfs(1);
}
94. 递归实现排列型枚举
94. 递归实现排列型枚举
初步, 不正确, 只能搜出来 1 2 3 这条路径
#include <iostream>
#include <cstring>
#include <algorithm>
#define tt int t; cin >> t; while(t -- ) run();
using namespace std;
const int N = 9;
bool st[N];
int path[N];
int cnt;
int n;
void dfs(int u)
{
if(u > n)
{
for(int i = 0; i < cnt; i ++ ) cout << path[i] <<' ';
puts("");
return ;
}
for(int i = 1; i <= n; i ++ )
{
if(!st[i])
{
st[i] = true;
path[cnt ++ ] = i;
dfs(u + 1);
// st[i] = false;
// dfs(u + 1);
}
}
}
int main()
{
cin >> n;
dfs(1);
}
正解
#include <iostream>
#include <cstring>
#include <algorithm>
#define tt int t; cin >> t; while(t -- ) run();
using namespace std;
const int N = 9;
bool st[N];
int path[N];
int cnt;
int n;
void dfs(int u)
{
if(u > n)
{
for(int i = 1; i <= n; i ++ ) cout << path[i] <<' ';
puts("");
return ;
}
for(int i = 1; i <= n; i ++ )
{
if(!st[i])
{
st[i] = true;
path[u] = i;
dfs(u + 1);
path[u] = 0;
st[i] = false;
}
}
}
int main()
{
cin >> n;
dfs(1);
}
1112. 迷宫
这里回溯是回溯到 遇到死路的那条链有分叉的地方, 在分叉那里继续往下搜
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int n;
int x1, y1, x2, y2;
char g[N][N];
bool st[N][N];
int dfs(int sx, int sy)
{
// chu shu hua
st[sx][sy] = true;
if(g[sx][sy] == '#') return 0; // 注意特殊判断
if(sx == x2 && sy == y2) return 1;
// ju xiang hua
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
for(int i = 0; i < 4; i ++ )
{
int a = sx + dx[i], b = sy + dy[i];
//deb2(a, b);
if(a < 0 || a >= n || b < 0 || b >= n) continue;
if(g[a][b] == '#' || st[a][b]) continue;
st[a][b] = true;
if(dfs(a, b)) return 1; // 注意形成一条链, 及时返回
st[a][b] = true;
}
return 0;
}
void run()
{
cin >> n;
for(int i = 0; i < n; i ++ ) cin >> g[i];
cin >>x1 >> y1 >> x2 >> y2;
memset(st, 0, sizeof st);
if(dfs(x1, y1))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
int main()
{
int T;
cin >> T;
while(T -- ) run();
}
1116. 马走日
这里的回溯 当遍历当不能走的时候 (所有点能遍历的都遍历了) , 才能回溯
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10;
int n, m, x, y, cnt;
bool st[N][N];
int ans;
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
void dfs(int x, int y, int cnt)
{
if(cnt == n * m)
{
ans ++;
return ;
}
st[x][y] = true;
for(int i = 0; i < 8; i ++ )
{
int a = dx[i] + x, b = dy[i] + y;
if(a < 0 || a >= n || b < 0 || b >= m) continue;
if(st[a][b]) continue;
dfs(a, b, cnt + 1);
}
st[x][y] = false;
}
void run()
{
cin >> n >> m >> x >> y;
memset(st, 0, sizeof st);
ans = 0;
dfs(x, y, 1); // 有一个点放进去, 不然永远判断不完
cout << ans << endl;
}
int main()
{
int T;
cin >> T;
while(T -- ) run();
return 0;
}
1117. 单词接龙
/* 保留 max
只能能接的就接 -> 直到不能接为止, 保留一个最大值;
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#define deb(x) cout << #x << "=" << x << endl
#define deb2(x, y) cout << #x << "=" << x << "," << #y << "=" << y << endl
#define deb3(x, y, z) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << endl
#define deb4(x, y, z, w) cout << #x << "=" << x << "," << #y << "=" << y <<","<< #z << "=" << z << ","<< #w << "=" << w << endl
#define debv(v) for(auto x:v) cout<<x<<" "
#define yes cout << 'Y' << 'E' << 'S' << endl
#define no cout << 'N' << 'O' << endl
#define gg exit(0);
using namespace std;
const int N = 21;
int g[N][N];
string word[N];
int used[N];
int n, ans;
// dfs 用于拼接 dragon, 同时记录每个单词的用的情况
void dfs(string dragon, int last)
{
ans = max((int)dragon.size(), ans); // max比较的两个类型必须一致
used[last] += 1;
for(int i = 0; i < n; i ++ )
if(g[last][i] && used[i] < 2)
dfs(dragon + word[i].substr(g[last][i]), i);
used[last] -= 1;
}
int main()
{
cin >> n;
for(int i = 0; i < n; i ++ ) cin >> word[i];
char start;
cin >> start;
for(int i = 0; i < n; i ++ )
for(int j = 0; j < n; j ++ )
{
string a = word[i], b = word[j];
for(int k = 1; k < min(a.size(), b.size()); k ++ ) // 从倒数第一个开始
{
if(a.substr(a.size() - k, k) == b.substr(0, k))
{
g[i][j] = k;
break;
}
}
}
// 找到可以拼接的位置, 拼接一下, 同时记录当前是哪个单词
for(int i = 0; i < n; i ++ )
if(word[i][0] == start)
dfs(word[i], i);
cout << ans;
return 0;
}