2024算法基础公选课练习五(DFS2)
一、前言
因为此次题目较多,我也不想分成两篇博客来发,我就直接给代码了,如果题目有需要强调的地方再特殊说明
二、题目总览
三、具体题目
3.1 问题 A: 勘探油田
我的代码
8方向的flood fill模型
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1e2+5,M = 1e6+5,INF = 0x3f3f3f3f;
int ans;
struct Node{
int _x,_y;
};
int n,m;
int dx[] = {0,1,1,1,0,-1,-1,-1};
int dy[] = {1,1,0,-1,-1,-1,0,1};
std::vector<std::vector<char>> g(N,std::vector<char>(N));
std::vector<std::vector<bool>> vis(N,std::vector<bool>(N,false));
void bfs(int x,int y){
std::queue<Node> q;
Node t;
t._x = x,t._y = y;
q.emplace(t);
vis[x][y] = true;
++ans;
while(!q.empty()){
auto t = q.front();
q.pop();
for(int i = 0;i<8;++i){
int u = t._x+dx[i],v = t._y+dy[i];
if(u<1||u>n||v<1||v>m||vis[u][v]||g[u][v]=='*') continue;
vis[u][v] = true;
Node t1;
t1._x = u,t1._y = v;
q.emplace(t1);
}
}
}
void solve(){
while(std::cin >> n >> m){
if(n==0&&m==0) break;
vis.assign(N,std::vector<bool>(N,false));
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
std::cin >> g[i][j];
}
}
ans = 0;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
if(g[i][j]=='@'&&!vis[i][j]){
bfs(i,j);
}
}
}
std::cout << ans << '\n';
}
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
int t = 1;
// std::cin >> t;
while(t--){
solve();
}
return 0;
}
3.2 问题 B: 景区旅游
我的代码
一次dfs即可
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 15,INF = 0x3f3f3f3f;
int n,m;
std::vector<std::vector<char>> g(N,std::vector<char>(N));
std::vector<std::vector<bool>> vis(N,std::vector<bool>(N,false));
int dx[] = {1,-1,0,0};
int dy[] = {0,0,1,-1};
int ans1 = 0,ans2 = INF;
struct node{
int _x,_y,_s;
}t,t1;
int sx,sy,ex,ey;
std::queue<node> q;
void dfs(int u,int x,int y){
if(x==ex&&y==ey){
ans1 = std::max(ans1,u);
ans2 = std::min(ans2,u);
return;
}
for(int i = 0;i<4;++i){
int x1 = x+dx[i],y1 = y+dy[i];
if(x1<1||x1>n||y1<1||y1>m||vis[x1][y1]||g[x1][y1]=='0') continue;
vis[x1][y1] = true;
dfs(u+1,x1,y1);
vis[x1][y1] = false;
}
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cin >> n >> m;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
std::cin >> g[i][j];
if(g[i][j]=='S'){
sx=i,sy=j;
}else if(g[i][j]=='E'){
ex=i,ey=j;
}
}
}
vis[sx][sy] = true;
dfs(0,sx,sy);
std::cout << ans1 << ' ' << ans2 << '\n';
return 0;
}
3.3 问题 C: 搜索与回溯——迷宫问题
我的代码
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 15,M = 1e6+5,INF = 0x3f3f3f3f;
int g[N][N];
bool vis[N][N];
int dx[] = {0,1,1,1,0,-1,-1,-1};
int dy[] = {1,1,0,-1,-1,-1,0,1};
int n;
int sx,sy,ex,ey,ans;
void dfs(int x,int y){
if(x==ex&&y==ey){
++ans;
return;
}
for(int i = 0;i<8;++i){
int u = x+dx[i],v = y+dy[i];
if(u<1||u>n||v<1||v>n||vis[u][v]||g[u][v]==1) continue;
vis[u][v] = true;
dfs(u,v);
vis[u][v] = false;
}
}
void solve(){
std::cin >> n;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=n;++j){
std::cin >> g[i][j];
}
}
sx = 1,sy = 1,ex = 1,ey = n;
vis[sx][sy] = true;
dfs(sx,sy);
std::cout << ans << '\n';
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
int t = 1;
// std::cin >> t;
while(t--){
solve();
}
return 0;
}
3.4 问题 D: 搜索——魔法卷轴
我的代码
dfs的时候需要多加一个列是否已经有手印的判断
#include <bits/stdc++.h>
using i64 = long long;
int n,m,res;
char a[15][15];
bool b[15];
void dfs(int k,int s){
if(s>=m){
res+=1;
return;
}
if(k>n){
return;
}
for(int i=1;i<=n;i++){
if(a[k][i] == '@' && b[i]==0){
b[i]=1;
dfs(k+1,s+1);
b[i]=0;
}
}
dfs(k+1,s);
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cin>>n>>m;
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
std::cin>>a[i][j];
}
}
res=0;
dfs(1,0);
std::cout << res<< '\n';
return 0;
}
3.5 问题 E: 搜索与回溯——N 皇后问题
我的代码
经典dfs
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 20;
int n;
char graph[N][N];
bitset<N> col,dg,adg;//column,diagonal,against the diagonal line
void dfs(int dep){
if(dep==n){
for(int i = 0;i<n;i++){
for(int j = 0;j<n;j++){
if(graph[i][j]=='Q'){
cout << j+1 << " \n"[i==n-1];
break;
}
}
}
return;
}
for(int i = 0;i<n;i++){
if(!col[i]&&!dg[dep+i]&&!adg[n+i-dep]){
col[i]=dg[dep+i]=adg[n+i-dep]=1;
graph[dep][i]='Q';
dfs(dep+1);
col[i]=dg[dep+i]=adg[n+i-dep]=0;
graph[dep][i]='.';
}
}
}
void solve(){
cin >> n;
for(int i = 0;i<n;i++) for(int j = 0;j<n;j++) graph[i][j]='.';
if(n!=3) dfs(0);
else{
cout << "no solute!\n";
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T = 1;
// cin >> T;
while(T--){
solve();
}
return 0;
}
3.6 问题 F: 搜索与回溯——工作分配问题
我的代码
使用next_permutation生成全排列暴力枚举
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1e5+5,M = 1e6+5,INF = 0x3f3f3f3f;
int c[25][25];
int n,ans = INF;
void solve(){
std::cin >> n;
for(int i = 1;i<=n;++i) for(int j = 1;j<=n;++j) std::cin >> c[i][j];
std::vector<int> v(n,0);
std::iota(v.begin(),v.end(),1);
do{
int sum = 0;
for(int i = 1;i<=n;++i){
sum+=c[i][v[i-1]];
}
ans = std::min(ans,sum);
}while(std::next_permutation(v.begin(),v.end()));
std::cout << ans << '\n';
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
int t = 1;
// std::cin >> t;
while(t--){
solve();
}
return 0;
}
3.7 问题 G: 观星
我的代码
题目讲得有点模糊,不过分析一下样例应该就能明白
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1505,M = 1e6+5,INF = 0x3f3f3f3f;
int n,m;
struct Node{
int x,y;
}t,t1;
int dx[] = {0,1,1,1,0,-1,-1,-1};
int dy[] = {1,1,0,-1,-1,-1,0,1};
char g[N][N];
bool vis[N][N];
int cnt=0,maxn=-1;
struct xingzuo{
int sx,sy,cnt;
};
std::vector<xingzuo> ans;
void bfs(int sx,int sy){
std::queue<Node> q;
t.x = sx,t.y = sy;
q.emplace(t);
vis[sx][sy] = true;
int cnt_ = 0;
while(!q.empty()){
auto t = q.front();
q.pop();
++cnt_;
for(int i = 0;i<8;++i){
int u = t.x+dx[i],v = t.y+dy[i];
if(u<1||u>n||v<1||v>m||vis[u][v]||g[u][v]=='.') continue;
vis[u][v] = true;
t1.x = u,t1.y = v;
q.emplace(t1);
}
}
xingzuo tmp;
tmp.sx = sx,tmp.sy = sy,tmp.cnt = cnt_;
ans.emplace_back(tmp);
}
void solve(){
std::cin >> n >> m;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
std::cin >> g[i][j];
}
}
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
if(g[i][j]=='*'&&!vis[i][j]){
++cnt;
bfs(i,j);
}
}
}
std::set<int> set;
std::map<int,int> map;
int res = 0;
for(const auto &ansi:ans){
set.insert(ansi.cnt);
map[ansi.cnt]++;
}
for(const auto &mpi:map){
res = std::max(res,mpi.first*mpi.second);
}
std::cout << set.size() << ' ' << res << '\n';
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
int t = 1;
// std::cin >> t;
while(t--){
solve();
}
return 0;
}
3.8 问题 H: 搜索与回溯——字符序列
我的代码
#include <bits/stdc++.h>
using i64 = long long;
std::vector<char> s(15);
int n,ans;
void dfs(int u) {
if(u==n+1) {
++ans;
return;
}
for(char c = 'A';c<='C';++c) {
s[u] = c;
if(u==1||s[u]!=s[u-2]||s[u-1]!=s[u-3]) {
dfs(u+1);
}else {
s[u] = 0;
}
}
}
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cin >> n;
dfs(1);
std::cout << ans << '\n';
return 0;
}
3.9 问题 I: 图的m着色问题(N26)
我的代码
#include<bits/stdc++.h>
using namespace std;
constexpr int N = 1e4+5,M = 1e3+5;
int n,k,m,a[N],b[M][M],ans;
bool check(int s){
for(int i=1;i<=s;i++){
if(b[i][s]&&a[i]==a[s]){
return false;
}
}
return true;
}
void dfs(int s){
if(s>n){
++ans;
return;
}
for(int i=1;i<=m;i++){
a[s]=i;
if(check(s)) dfs(s+1);
else a[s]=0;
}
}
int main(){
cin.tie(nullptr)->sync_with_stdio(false);
int T = 1;cin >> T;
while(T--){
memset(b,0,sizeof b);
memset(a,0,sizeof a);
ans = 0;
cin>>n>>k>>m;
while(k--){
int x,y;
cin >> x >> y;
b[x][y] = 1;
}
dfs(1);
cout << ans << '\n';
}
return 0;
}
3.10 问题 J: 搜索与回溯——部落卫队
我的代码
参考了另外一篇博客的写法
#include<cstdio>
#include<cstring>
struct vellager{
int other[105],s;
} vec[105];
int m,n,send;
bool can[105],use[105],end[105];
void flag(int x,int tot){
if(x>n){
if(tot>send){
send=tot;
memcpy(end,use,n+1);
}
return;
}
if(!can[x] && !use[x]){
use[x]=true;
bool now[105];
memcpy(now,can,n+1);
for(int j=0;j<vec[x].s;j++) can[vec[x].other[j]]=true;
flag(x+1,tot+1);
use[x]=false;
memcpy(can,now,n+1);
}
flag(x+1,tot);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int x,y;scanf("%d%d",&x,&y);
if(!vec[x].other[0]) vec[x].s=0;
if(!vec[y].other[0]) vec[y].s=0;
vec[x].other[vec[x].s++]=y;
vec[y].other[vec[y].s++]=x;
}
flag(1,0);
printf("%d\n",send);
for(int i=1;i<=n;i++) i-1?printf(" %d",end[i]):printf("%d",end[i]);
return 0;
}
3.11 问题 K: 植物大战僵尸现实版
我的代码
第二次出现这个题了,老师把数据范围改正确了x和y都介于1到1e9之间
思路还是dfs枚举行的状态,然后贪心判断列是否修改,最后答案取max即可
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1e5+5,M = 1e6+5,INF = 0x3f3f3f3f;
std::vector<std::vector<i64>> g(15,std::vector<i64>(205,0));
std::vector<std::vector<i64>> tmp(15,std::vector<i64>(205,0));
std::vector<int> v(15,0);
std::vector<i64> pre(205,0);
i64 n,m,x,t;
i64 ans=0;
void dfs(int u){
if(u==n+1){
i64 cnt = 0;
for(int i = 1;i<=n;++i) cnt+=v[i]?1:0;
if(cnt>t) return;
std::copy(tmp.begin(),tmp.end(),g.begin());
pre.assign(205,0);
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
g[i][j] = v[i]?x:g[i][j];
}
}
for(int i = 1;i<=m;++i){
for(int j = 1;j<=n;++j){
pre[i]+=g[j][i];
}
}
i64 sum = 0;
std::sort(pre.begin()+1,pre.begin()+1+m);
for(int i = 1;i<=m;++i){
if(cnt<t&&pre[i]<x*n){
sum+=x*n;
++cnt;
}else{
sum+=pre[i];
}
}
ans = std::max(ans,sum);
return;
}
v[u] = 0;
dfs(u+1);
v[u] = 1;
dfs(u+1);
}
void solve(){
std::cin >> n >> m >> x >> t;
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
std::cin >> g[i][j];
}
}
std::copy(g.begin(),g.end(),tmp.begin());
dfs(1);
std::cout << ans << '\n';
}
int main(){
std::cin.tie(nullptr)->sync_with_stdio(false);
int t = 1;
// std::cin >> t;
while(t--){
solve();
}
return 0;
}
3.12 问题 L: 袜子配对
我的代码
思路同牛客小白月赛105的D题,跳转链接
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 2e5+5;
int n,m,k;
std::vector<int> colors(N,0);
struct DSU {
int _n;
std::vector<int> _fa,_size;
DSU(){}
DSU(int n){
init(n);
}
void init(int n) {
_fa.resize(n);
std::iota(_fa.begin(),_fa.end(),0);
_size.assign(n,1);
}
int find(int x) {
if(x!=_fa[x]) {
_fa[x] = find(_fa[x]);
}
return _fa[x];
}
bool same(int x,int y) {
return find(x)==find(y);
}
bool merge(int x,int y) {
int fx = find(x);
int fy = find(y);
if(fx!=fy) {
_size[fx]+=_size[fy];
_fa[fy] = fx;
return true;
}
return false;
}
};
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
std::cin >> n >> m >> k;
DSU dsu(N);
for(int i = 1;i<=n;++i) {
std::cin >> colors[i];
}
int ans = 0;
while(m--) {
int l,r;std::cin >> l >> r;
if(dsu.merge(colors[l],colors[r])) {
++ans;
}
}
std::cout << ans << '\n';
return 0;
}
3.13 问题 M: 素数树
我的代码
突然发现自己代码逻辑错了,但是仍然能AC,说明后台测试点的数据不够刁钻,等我修改一下后续再把代码放上来
正确的思路应该是判断该树是否为二叉树,如果是的话,那么只需要对相邻的边依次输出2和3即可;如果不是的话,输出-1然后return处理下一组即可