Living-Dream 系列笔记 第8期
本期主要讲解的与上期相同。
例题
T1
上课的时候调这个题感觉要吐了 \(qwq\)。。。
首先读入 \(n\) 行字符串,可以采取忽略中间无关单词的方式来直接读取 \(X\) 和 \(Y\)。
将所有名字存入 \(a\) 数组,对 \(a\) 数组按字典序排序后就可以开始 \(\text{DFS}\) 了,这里建议使用 next_premutation
。
设计一个 check
函数来判定当前全排列是否满足 \(n\) 条限制。具体实现:
-
遍历 \(n\) 条限制,对于第 \(i\) 条限制,在 \(8\) 个名字中找到对应的 \(X_i\) 和 \(Y_i\),保存它们的位置。
-
判断它们位置的绝对差是否 \(=1\)(相邻)即可。
#include<bits/stdc++.h> using namespace std; int n; string x[8],y[8]; string ans[8]={"Beatrice","Belinda","Bella","Bessie","Betsy","Blue","Buttercup","Sue"}; int getpos(string x){ int p; for(int i=0;i<8;i++) if(ans[i]==x){ p=i; break; } return p; } bool check(){ for(int i=1;i<=n;i++){ int p1=getpos(x[i]),p2=getpos(y[i]); if(abs(p1-p2)!=1) return 0; } return 1; } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>x[i]; for(int j=1;j<=5;j++) cin>>y[i]; } do{ if(check()){ for(int i=0;i<8;i++) cout<<ans[i]<<'\n'; break; } }while(next_permutation(ans,ans+8)); return 0; }
习题
T2
一个矩阵有主对角线(左上到右下)和副对角线(右上到左下),主对角线经过点的 \(x,y\) 坐标差一定,副对角线则是和一定。
于是我们可以记录三个 \(bool\) 数组 \(c,m,e\),分别记录在当前列 / 主对角线 / 副对角线是否能放置皇后。
在 \(\text{dfs(x)}\) 中我们定义行为格子,列为填入的数字,那么此题就变成了一个全排列问题。在 \(1 \sim n\) 遍历填入哪一列时,我们仅需判断 \(c_i,m_{x-i+n},e_{x_i}\) 是否均为 \(false\),若是则可以放置皇后。
注意回溯。
#include<bits/stdc++.h> using namespace std; int n,sum,ans[31]; int col[31],m[31],e[31]; void dfs(int x){ if(x==n+1){ sum++; if(sum<=3){ for(int i=1;i<=n;i++) cout<<ans[i]<<' '; cout<<'\n'; } return; } for(int i=1;i<=n;i++){ if(!col[i]&&!m[x-i+n]&&!e[x+i]){ col[i]=m[x-i+n]=e[x+i]=1; ans[x]=i; dfs(x+1); col[i]=m[x-i+n]=e[x+i]=0; } } } int main(){ cin>>n; dfs(1); cout<<sum; return 0; }
T3
考虑指数型枚举,即填格子时仅有填 / 不填两种选择,时间复杂度 \(O(2^n)\)。
在 \(\text{DFS}\) 函数中传入两个参数:\(x\) 和 \(tot\),分别记录即将填的格子数以及已经填完的格子数。
当 \(x=g+1\) 时,若符合要求且 \(tot <\) 全局答案,则更新全局答案并将当前选择方案 \(copy\) 给全局选择方案。
对于判断某一方案是否合法,则可以对于所有选择的种类,依次判断每一列之和是否 \(<\) 每头牛需要的维他命,若是则返回 \(1\);若均 \(\ge\) 所需维他命,则返回 \(1\)。
#include<bits/stdc++.h> using namespace std; int v,g,minn=1e9+31; int ans[31],Ans[31]; int a[31],b[31][31]; bool check(int tot){ for(int j=1;j<=v;j++){ int sum=0; for(int i=1;i<=tot;i++) sum+=b[ans[i]][j]; if(sum<a[j]) return 0; } return 1; } void dfs(int x,int tot){ if(x==g+1){ if(check(tot)){ if(tot<minn){ minn=tot; for(int i=1;i<=minn;i++) Ans[i]=ans[i]; } } return; } ans[tot+1]=x; dfs(x+1,tot+1); dfs(x+1,tot); } int main(){ cin>>v; for(int i=1;i<=v;i++) cin>>a[i]; cin>>g; for(int i=1;i<=g;i++) for(int j=1;j<=v;j++) cin>>b[i][j]; dfs(1,0); cout<<minn<<' '; for(int i=1;i<=minn;i++) cout<<Ans[i]<<' '; return 0; }
T4
建立一个 \(b\) 数组保存下标,对 \(b\) 数组进行枚举全排列来遍历所有的顺序。
对于每一种顺序,遍历 \(n\) 个点,通过对上 / 下 / 左 / 右 / 离它最近的油的边界与它的距离取 \(\min\) 来得到在第 \(i\) 个点的最大半径,累加所有 \(n\) 格点的半径,用总面积减去就得到了剩余面积,对所有这样的剩余面积取 \(\min\) 即可。
注意精度问题。
#include<bits/stdc++.h> using namespace std; int n,ans=1e9+31; double S,up,down,lft,rgt; double x,y,xx,yy; double rr[31]; struct node{ int a,b; }p[31]; int id[31]; double dist(int aa,int bb){ return sqrt((p[aa].a-p[bb].a)*(p[aa].a-p[bb].a)+(p[aa].b-p[bb].b)*(p[aa].b-p[bb].b)); } double surf(){ double sum=0.0; for(int i=1;i<=n;i++){ double u=up-p[id[i]].b,d=p[id[i]].b-down,l=p[id[i]].a-lft,r=rgt-p[id[i]].a; double t=1e9; for(int j=i-1;j>=1;j--) t=min(t,dist(id[i],id[j])-rr[j]); if(t<0){ rr[i]=0; continue; } rr[i]=min(u,min(d,min(l,min(r,t)))); sum+=rr[i]*rr[i]*3.1415926; } return sum; } int main(){ cin>>n; cin>>x>>y>>xx>>yy; for(int i=1;i<=n;i++){ cin>>p[i].a>>p[i].b; id[i]=i; } up=max(y,yy),down=min(y,yy),lft=min(x,xx),rgt=max(x,xx); S=(up-down)*(rgt-lft); do{ double sf=surf(); ans=min(ans,(int)(round(S-sf))); }while(next_permutation(id+1,id+n+1)); cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)