1. 92.递归实现指数型枚举
时间复杂度:O(n* 2 n 2^n 2n)
#include <bits/stdc++.h>
using namespace std;
const int N=16;
int n;
int st[N];
void dfs(int u)//u表示当前在做第几位
{
if(u>n)
{
for(int i=1;i<=n;i++)
if(st[i]==1) printf("%d ",i);
puts("");
return;
}
//枚举每一位的两种情况:1选 2不选
st[u]=2;
dfs(u+1);
st[u]=0;
st[u]=1;
dfs(u+1);
st[u]=0;
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
2.94. 递归实现排列型枚举
#include <bits/stdc++.h>
using namespace std;
const int N=10;
int state[N];//存放当前这一位的数
bool used[N];//记录哪个数用没用
int n;
void dfs(int u)
{
if(u>n)
{
for(int i=1;i<=n;i++) printf("%d ",state[i]);
puts("");
return;
}
for(int i=1;i<=n;i++)
if(!used[i])
{
state[u]=i;
used[i]=true;
dfs(u+1);
state[u]=0;
used[i]=false;
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
3.93. 递归实现组合型枚举
方法一:模拟排列型枚举,多加一条判断语句【自己写的,贼慢】
#include <bits/stdc++.h>
using namespace std;
const int N=25;
int state[N];
bool used[N];
int n,m;
void dfs(int u)
{
if(u>m)
{
for(int i=1; i<=m; i++) printf("%d ",state[i]);
puts("");
return;
}
for(int i=1; i<=n; i++)
{
if(!used[i])
{
state[u]=i;
if(u>1&&state[u]<state[u-1]) continue;
used[i]=true;
dfs(u+1);
state[u]=0;
used[i]=false;
}
}
}
int main()
{
cin>>n>>m;
dfs(1);
return 0;
}
方法二:y总全新搜索方式
#include <bits/stdc++.h>
//与排列型的区别:不需要used数组,每次都比当前的数大的一位开始取
using namespace std;
const int N=30;
int n,m;
int way[N];
void dfs(int u,int start)//枚举第u位,从u位上的数字+1开始
{
if(u+n-start<m) return;//剪枝:已经选好的数+可以选的数<应该选的数
if(u==m+1)
{
for(int i=1;i<=m;i++) printf("%d ",way[i]);
puts("");
return;
}
for(int i=start;i<=n;i++)
{
way[u]=i;
dfs(u+1,i+1);
way[u]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);
dfs(1,1);
return 0;
}
4.1209. 带分数
dfs爆搜写法【by myself】
#include <bits/stdc++.h>
using namespace std;
int st[10];
bool used[10];
int m,res;
int strnu(int a[],int be,int en)
{
int x=0;
for(int i=be; i<=en; i++)
{
x=x*10+a[i];
}
return x;
}
void dfs(int u)//9个数全排列
{
int n=9;
if(u>n)//得到了全排列
{ //循环时枚举要保证有3个数
for(int i=1; i<n-1; i++)
{
for(int j=i+1; j<n; j++)
{
int a=strnu(st,1,i);
int b=strnu(st,i+1,j);
int c=strnu(st,j+1,n);
if(a*c+b==c*m) res++;//除法的巧妙转化
}
}
return;
}
for(int i=1; i<=n; i++)
{
if(!used[i])
{
st[u]=i;
used[i]=true;
dfs(u+1);
st[u]=0;
used[i]=false;
}
}
}
int main()
{
scanf("%d",&m);
dfs(1);
printf("%d\n",res);
return 0;
}
y总dfs嵌套写法
#include <bits/stdc++.h>
using namespace std;
const int N=10;
int n;
bool st[N],backup[N];
int ans;
bool check(int a,int c)
{
long long b=n*(long long)c-a*c;
if(!a||!b||!c) return false;
memcpy(backup,st,sizeof st);
while(b)//把b的每一位都抠出来
{
int x=b%10;
b/=10;
if(!x||backup[x]) return false;
backup[x]=true;
}
for(int i=1;i<=9;i++)
if(!backup[i]) return false;
return true;
}
void dfs_c(int u,int a,int c)
{
if(u>9) return;
if(check(a,c)) ans++;
for(int i=1;i<=9;i++)
if(!st[i])
{
st[i]=true;
dfs_c(u+1,a,c*10+i);
st[i]=false;
}
}
void dfs_a(int u,int a)
{
if(a>=n) return;//直接没解
if(a) dfs_c(u,a,0);
for(int i=1;i<=9;i++)
if(!st[i])
{
st[i]=true;
dfs_a(u+1,a*10+i);
st[i]=false;
}
}
int main()
{
cin>>n;
dfs_a(0,0);
cout<<ans<<endl;
return 0;
}
5.717. 简单斐波那契
递推版本
#include <bits/stdc++.h>
using namespace std;
const int N=50;
int f[N];
int main()
{
f[1]=0,f[2]=1;
int n;
cin>>n;
for(int i=3;i<=n;i++) f[i]=f[i-1]+f[i-2];
for(int i=1;i<=n;i++) printf("%d ",f[i]);
return 0;
}
滚动数组版
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a = 0, b = 1;
int n;
cin >> n;
for (int i = 0; i < n; i ++ )
{
cout << a << ' ';
int c = a + b;
a = b, b = c;
}
cout << endl;
return 0;
}
6.95. 费解的开关【妙啊】
#include <bits/stdc++.h>
using namespace std;
const int N=6;
char g[N][N],backup[N][N];
int dx[5]={-1,0,1,0,0},dy[5]={0,1,0,-1,0};
void turn(int x,int y)//如何操作(x,y)格子及其四周使得01互换
{
for(int i=0;i<5;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=5||b<0||b>=5) continue;
g[a][b]^=1;
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
for(int i=0;i<5;i++) cin>>g[i];//先输入棋盘,字符串型
int res=10;//记步数
for(int op=0;op<32;op++)//枚举第一行灯的操作
{
memcpy(backup,g,sizeof g);
int step=0;
for(int i=0;i<5;i++)//看看第一行每一个格子是否需要操作
if(op>>i&1)
{
step++;
turn(0,i);
}
for(int i=0;i<4;i++)//下面的n-1行的操作都唯一确定了
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) res=min(res,step);
memcpy(g,backup,sizeof g);
}
if(res>6) res=-1;
cout<<res<<endl;
}
return 0;
}
7.费解的开关升级版——116.飞行员兄弟
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=5;
char g[N][N],backup[N][N];
int get(int x,int y)//二维数组到一维的映射
{
return x*4+y;
}
void turn_one(int x,int y)
{
if(g[x][y]=='+') g[x][y]='-';
else g[x][y]='+';
}
void turn_all(int x,int y)
{
for(int i=0;i<4;i++)
{
turn_one(x,i);
turn_one(i,y);
}
turn_one(x,y);
}
int main()
{
for(int i=0; i<4; i++)
cin>>g[i];
vector<PII> res;
for(int op=0; op<1<<16; op++)
{
vector<PII> temp;
memcpy(backup,g,sizeof g);
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(op>>get(i,j)&1)
{
temp.push_back({i,j});
turn_all(i,j);
}
bool has_closed=false;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(g[i][j]=='+')
has_closed=true;
if(has_closed==false)
{
if(res.empty()||res.size()>temp.size()) res=temp;
}
memcpy(g,backup,sizeof g);
}
cout<<res.size()<<endl;
for(auto p: res)
printf("%d %d\n",p.first+1,p.second+1);
return 0;
}