5.10总结
第一题:B3621 枚举元组
思路:
通过递归生成每个位置的可能值(1到k),DFS按字典序遍历所有可能。每个位置从1到k依次填入,递归处理后续位置,确保生成的元组按字典序排列。
重难点:
- 字典序生成:DFS自然按顺序生成,无需额外处理。
- 递归设计:每个递归层处理一个位置,循环遍历所有可能值。
正确代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
int vis[maxn],aaa[maxn];
void dfs(int x,int ans[]){
if(x>m){
for(int i=1;i<=m;i++){
cout<<ans[i]<<' ';
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
ans[x]=i;
dfs(x+1,ans);
}
}
signed main(){
cin>>m>>n;
aaa[0]=1;
dfs(1,aaa);
return 0;
}
第二题:B3622 枚举子集
思路:
递归枚举每个元素的选(Y)与不选(N),按先N后Y的顺序确保字典序。每次递归处理一个元素,最终输出所有可能的子集。
重难点:
- 字典序控制:先递归不选的情况,再处理选的情况。
- 状态回溯:无需显式回溯,直接覆盖字符数组。
正确代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
char vis[maxn];
void dfs(int x){
if(x>n){
for(int i=1;i<=n;i++){
cout<<vis[i];
}
cout<<endl;
return;
}
vis[x]='N';
dfs(x+1);
vis[x]='Y';
dfs(x+1);
}
signed main(){
cin>>n;
dfs(1);
return 0;
}
第三题:P1157 组合的输出
思路:
递归生成组合,确保元素递增。每次从上一个元素的下一个位置开始选择,避免重复。使用setw控制输出格式。
重难点:
- 递增组合生成:维护当前选择的起始值。
- 输出格式:每个元素占3字符宽度。
正确代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
int vis[maxn],aaa[maxn];
void dfs(int x,int ans[]){
if(x>m){
for(int i=1;i<=m;i++){
cout<<setw(3)<<ans[i];
}
cout<<endl;
return;
}
for(int i=ans[x-1];i<=n;i++){
if(vis[i]==0){
vis[i]=1;
ans[x]=i;
dfs(x+1,ans);
vis[i]=0;
}
}
}
signed main(){
cin>>n>>m;
aaa[0]=1;
dfs(1,aaa);
return 0;
}
第四题:P1706 全排列问题
思路:
回溯法生成全排列,使用标记数组避免重复选择。每次递归选择一个未被使用的元素,处理完恢复状态。
重难点:
- 全排列生成:维护标记数组,确保元素不重复。
- 输出格式:每个元素占5字符宽度。
正确代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int n,m;
int vis[maxn],ans[maxn];
void dfs(int x){
if(x>n){
for(int i=1;i<=n;i++){
cout<<setw(5)<<ans[i];
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(vis[i]==0){
vis[i]=1;
ans[x]=i;
dfs(x+1);
vis[i]=0;
}
}
}
signed main(){
cin>>n;
dfs(1);
return 0;
}
第五题:P9416 Domino
思路:
将方案数m分解为斐波那契数的乘积,最小化总长度。DFS尝试所有可能的分解方式,计算最小总长度。
重难点:
- 数学模型:方案数对应斐波那契数的乘积。
- 因数分解:递归分解m,求最小总长度。
正确代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int a[maxn];
int n;
int ans=inf;
void dfs(int x,int sum){
if(x<=1){
ans=min(ans,sum-1);
return;
}
for(int i=2;i<=87;i++){
int tmp1=x;
int tmp2=sum;
if(tmp1%a[i]==0){
while(tmp1%a[i]==0){
tmp1/=a[i];
tmp2+=(i+1);
}
dfs(tmp1,tmp2);
}
}
}
signed main(){
cin>>n;
a[0]=1;
a[1]=1;
for(int i=2;i<=87;i++){
a[i]=a[i-1]+a[i-2];
}
dfs(n,0);
if(n==1){
cout<<1<<endl;
return 0;
}
if(ans==inf){
cout<<"NIE";
}
else{
cout<<ans;
}
return 0;
}
第六题:U417487 拆分子段
思路:
迭代加深DFS,每次生成可能的数列项,保证递增。剪枝优化:剩余步骤不足以达到目标时提前终止。
重难点:
- 最短路径搜索:迭代加深限制深度。
- 剪枝优化:基于当前最大值和剩余步骤。
正确代码:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int maxn=1e6+5,mod=1e9+7,inf=1e18;
int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
void write(int x){if(x<0){putchar('-'),x=-x;}if(x>9){write(x/10);}putchar(x%10+'0');return;}
int fpow(int a,int b,int p){if(b==0){return 1;}int res=fpow(a,b/2,p)%p;if(b%2==1){return((res*res)%p*a)%p;}else{return(res*res)%p;}}
int a[maxn],n,max_dep;
int mini=inf;
int dfs(int x){
if(x>max_dep){
return a[x-1]==n;
}
if(a[x-1]*(1ll<<(max_dep-x+1))<n){
return 0;
}
for(int i=0;i<x;i++){
for(int j=i;j<x;j++){
int t=a[i]+a[j];
if(t>n){
break;
}
if(t<=a[x-1]){
continue;
}
a[x]=t;
if(dfs(x+1)){
return 1;
}
}
}
return 0;
}
signed main(){
a[0]=1;
while(cin>>n&&n){
cout<<1;
for(max_dep=0;;max_dep++){
if(dfs(1)){
for(int i=1;i<=max_dep;i++){
cout<<' '<<a[i];
}
cout<<endl;
break;
}
}
}
return 0;
}
本人(KK_SpongeBob)蒟蒻,写不出好文章,但转载请注明原文链接:https://www.cnblogs.com/OIer-QAQ/p/18870655

浙公网安备 33010602011771号