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;
}
posted @ 2025-05-11 11:55  KK_SpongeBob  阅读(36)  评论(0)    收藏  举报