CH0301 递归实现指数型枚举
搜索与回溯,指数级算法。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
using namespace std;
vector<int>chosen;
int n;
void dfs(int x){
if(x==n+1){
for(unsigned i=0;i<chosen.size();++i)
printf("%d ",chosen[i]);
puts("");
return;
}
dfs(x+1);
chosen.push_back(x);
dfs(x+1);
chosen.pop_back();
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n);
dfs(1);
return 0;
}
CH0302 递归/非递归实现组合型枚举
搜索与回溯。要字典序最小,所以优先往加入当前节点的分支搜索。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
using namespace std;
vector<int> chosen;
unsigned n,m;
void dfs(unsigned x){
if(chosen.size()>m||chosen.size()+(n-x+1)<m)
return;
if(x==n+1){
for(unsigned i=0;i<chosen.size();++i)
printf("%d ",chosen[i]);
puts("");
return;
}
chosen.push_back(x);
dfs(x+1);
chosen.pop_back();
dfs(x+1);
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m);
dfs(1);
return 0;
}
CH0303 递归实现排列型枚举
搜索与回溯
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
int n,order[11];
bool chosen[11];
void dfs(int x){
if(x==n+1){
for(int i=1;i<=n;++i)
printf("%d ",order[i]);
puts("");
return;
}
for(int i=1;i<=n;++i)if(!chosen[i]){
chosen[i]=1,order[x]=i;
dfs(x+1);
chosen[i]=0;
}
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n);
dfs(1);
return 0;
}
CH0201 费解的开关
描述
你玩过“拉灯”游戏吗?25盏灯排成一个5x5的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字“1”表示一盏开着的灯,用数字“0”表示关着的灯。下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在6步以内使所有的灯都变亮。
做法
游戏有三个性质:
- 每个位置至多被点击一次。
- 若固定的第一行的点法,则满足题意的方案至多有一种。
- 点击的顺序不影响最终结果。
于是枚举第一行的点法,从第一行开始递推。
时间复杂度\(O(2^n n^2)\)。
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
co int N=10;
int g[N][N],n,ans,tmp[N][N];
void change(int x,int y){
tmp[x][y]^=1;
if(x-1) tmp[x-1][y]^=1;
if(y-1) tmp[x][y-1]^=1;
if(y+1<=n) tmp[x][y+1]^=1;
if(x+1<=n) tmp[x+1][y]^=1;
}
int t;
char s[N];
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(t);
n=5;
while(t--){
ans=25;
for(int i=1;i<=n;++i){
scanf("%s",s+1);
for(int j=1;j<=n;++j)
g[i][j]=(s[j]-'0')^1;
}
for(int s=0;s<(1<<n);++s){
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
tmp[i][j]=g[i][j];
bool ok=1;
int tmp=s,k=1,cnt=0;
while(tmp){
if(tmp&1) change(1,k),++cnt;
++k,tmp>>=1;
}
for(int j=2;j<=n;++j)
for(k=1;k<=n;++k)if(::tmp[j-1][k])
change(j,k),++cnt;
for(int j=1;j<=n;++j) if(::tmp[n][j]){
ok=0;
break;
}
if(ok) ans=std::min(ans,cnt);
}
if(ans>6) puts("-1");
else printf("%d\n",ans);
}
return 0;
}