算法基础模板整理(基础搜索篇)
递归实现枚举
递归实现指数型枚举
void dfs(int k){
if(k > n) {
for(auto &x : res) cout << x << ' ';
cout << endl; return;
}
dfs(k + 1);
res.push_back(k);
dfs(k + 1);
res.pop_back();
}
递归实现排列型枚举
void dfs(int k){
if(k > n){
for(int i = 1; i <= n; i ++ ) cout << a[i] << ' ';
cout << endl; return;
}
for(int i = 1; i <= n; i ++ ){
if(st[i]) continue;
st[i] = true;
a[k] = i;
dfs(k + 1);
st[i] = false;
}
}
递归实现组合型枚举
void dfs(int k){
int nn = res.size();
if(nn > m || m - nn > n - k + 1) return;
if(k > n){
for(auto &x : res) cout << x << ' ';
cout << endl;
}
res.push_back(k);
dfs(k + 1);
res.pop_back();
dfs(k + 1);
}
BFS求最短路
void bfs(){ // 经典二维数组中 bfs 求最短路
queue<pii> q;
q.push({0, 0});
vis[0][0] = true;
int res = 0;
while(!q.empty()){
int nn = q.size();
for(int i = 0; i < nn; i ++ ){
auto [x, y] = q.front();
q.pop();
if(x == n - 1 && y == m - 1) {
cout << res;
return;
}
for(int k = 0; k < 4; k ++ ){
int nx = x + dx[k], ny = y + dy[k];
if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if(vis[nx][ny] || g[nx][ny]) continue;
q.push({nx, ny});
vis[nx][ny] = true;
}
}
res ++ ; //也可开一个dist数组来记录最短路 且可以恰好省去vis数组
}
}
int bfs(){ // 树 or 图 上求点的层次
queue<int> q; q.push(1);
memset(d, -1, sizeof(d));
d[1] = 0;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = h[u]; i != -1; i = ne[i]){
int v = e[i];
if(d[v] != -1) continue;
q.push(v), d[v] = d[u] + 1;
}
}
return d[n];
}
DFS判断连通性
bool dfs(int x, int y){ //判断两点是否可达
vis[x][y] = true;
if(x == desx && y == desy) return true;
for(int k = 0; k < 4; k ++ ){
int nx = x + dx[k], ny = y + dy[k];
if(nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
if(vis[nx][ny] || g[nx][ny] == '#') continue;
if(dfs(nx, ny)) return true;
}
return false;
}
//----------------------------------------
void dfs(int x, int y){ //求连通块个数 也可用bfs
vis[x][y] = true;
for(int k = 0; k < 8; k ++ ){
int nx = x + dx[k], ny = y + dy[k];
if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if(vis[nx][ny] || g[nx][ny] == '#') continue;
dfs(nx, ny);
}
}
for(int i = 0; i < n; i ++ )
for(int j = 0; j < m; j ++ )
if(g[i][j] == '.' && !vis[i][j])
dfs(i, j), ans ++ ;
DFS求树的直径
int c; //记录第一次dfs得到的端点
void dfs(int u, int fa){
for(auto &[v, w] : e[u])
if(v != fa){
dist[v] = dist[u] + w;
if(dist[v] > dist[c]) c = v; //记录最远的点
dfs(v, u);
}
}
int main(){
cin >> n;
for(int i = 1; i < n; i ++ ){
int u, v, w; cin >> u >> v >> w;
e[u].push_back(make_pair(v, w));
e[v].push_back(make_pair(u, w));
}
dfs(1, 0); //找到一个端点c
dist[c] = 0;
dfs(c, 0); //找到c对应的端点
cout << dist[c];
}
DFS求树的重心
int dfs(int u){
vis[u] = true;
int sum = 1, res = 0;
for(int i = h[u]; i != -1; i = ne[i]){
int v = e[i];
if(!vis[v]){
int s = dfs(v);
res = max(res, s);
sum += s;
}
}
res = max(res, n - sum);//以u为起点向下的最大连通块 向上的连通块 较大者
ans = min(res, ans);
return sum;
}
回溯
DFS搜索经典案例(Acwing 1116.马走日)
void dfs(int x, int y, int cnt){
if(cnt == n * m){ //走满图中所有的点
res ++ ;
return;
}
for(int k = 0; k < 8; k ++ ){
int nx = x + dx[k], ny = y + dy[k];
if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if(vis[nx][ny]) continue;
vis[nx][ny] = true;
dfs(nx, ny, cnt + 1);
vis[nx][ny] = false;
}
}
DFS剪枝经典案例(Acwing 165.小猫爬山)
void dfs(int k, int cnt){
if(cnt >= res) return; //剪枝
if(k > n){
res = min(res, cnt);
return;
}
//枚举已有的车是否可存
for(int i = 1; i <= cnt; i ++ ){
if(t[i] + a[k] <= W){
t[i] += a[k];
dfs(k + 1, cnt);
t[i] -= a[k];
}
}
t[cnt + 1] += a[k];
dfs(k + 1, cnt + 1); //新开一辆车
t[cnt + 1] -= a[k];
}
状态压缩 递推
经典示例(Acwing 95.费解的开关)
void turn(int x, int y){
for(int k = 0; k < 5; k ++ ){
int nx = x + dx[k], ny = y + dy[k];
if(nx < 0 || nx >= 5 || ny < 0 || ny >= 5) continue;
g[nx][ny] ^= 1;
}
}
int main(){
int t; cin >> t;
while(t -- ){
for(int i = 0; i < 5; i ++ ) cin >> g[i];
int ans = 1e7;
for(int k = 0; k < 1 << 5; k ++ ){
int step = 0;
memcpy(backup, g, sizeof(g));
//枚举第一行如何操作
for(int i = 0; i < 5; i ++ )
if(k >> i & 1){
step ++ ;
turn(0, i);
}
//从第一行开始到第四行,依次改变下一行的对应位置的开关
for(int i = 0; i < 4; i ++ )
for(int j = 0; j < 5; j ++ )
if(g[i][j] == '0'){
step ++ ;
turn(i + 1, j);
}
//验证最后一行是否都是亮的
bool dark = false;
for(int i = 0; i < 5; i ++ )
if(g[4][i] == '0'){
dark = true;
break;
}
if(!dark) ans = min(ans, step);
memcpy(g, backup, sizeof(backup));
}
if(ans <= 6) cout << ans << endl;
else cout << -1 << endl;
}
}
一切都是命运石之门的选择,本文章来源于博客园,作者:MarisaMagic,出处:https://www.cnblogs.com/MarisaMagic/p/17317078.html,未经允许严禁转载