AcWingブルーブリッジカップ特別トレーニング:(1)再帰と再帰の例
AcWingアカウントID:Tiansuo Koji
注:yの合計コードとは異なる場合があります
- 指数列挙(マスター)を再帰的に実装して
、1からnまでの任意の数のn個の整数をランダムに選択します。この質問では、最終的に昇順で出力する必要があります。
y一般クラスでは、ツリー図を使用して検討できることが明確に指摘されています。各桁について、選択と非選択の2つのケースを導き出すことができます。2つのケースを検討した後、それらを検討します。次の桁を選択および選択解除します...など。これら2つのケースを別々に検討する限り、再帰的削減に注意してください。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=16;
int n;
vector<int>path;//记录最终答案
void dfs(int u)//u代表了当前是1-n中的哪一个数,由于输出需要从小到大,故从1开始
{
if(u == n+1)//如果这n位数都枚举完了,显然是枚举到第n+1个了
{
for(int i=0;i<path.size();i++)
{
cout<<path[i]<<" ";
}
cout<<endl;
return ;//递归终止,开始回溯
}
path.push_back(u);
dfs(u+1);//如果选了本位数,就push进去
path.pop_back();//递归还原
dfs(u+1);//如果没选本位数。
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
- 指数列挙(マスタリング)を再帰的に実装する問題では
、1-nの順序を乱す必要があり、同時に、小さい語彙の順序が最初に来る必要があります。したがって、を使用して1-nの各桁を列挙し、この桁を使用したことをマークします。ここでは、再帰的なアイデアを使用して解決します
。i= 1ビットの例を取り上げ、最初の数値を取り上げます。 i = 1を選択してパス配列にプッシュした後、i = 2-> nから数値を選択して、再帰的に次のレベルに進みます。
同様に、最初のレベルの再帰にi = 1ではないことを選択することもできます。最初の数値としてi = 2,3…nを選択し、繰り返しを防ぐためにマークを付けてから、マークされたことのない次のレベルに再帰することができます。勝者はあなたの次の桁です。再帰的な復元にも注意してください!
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=10;
int n;
vector<int>path;
bool st[N];
void dfs(int u)
{
if(u == n)
{
for(int i=0;i<path.size();i++)
{
cout<<path[i]<<" ";
}
cout<<endl;
return ;
}
for(int i=1;i<=n;i++)
{
if(!st[i])
{
path.push_back(i);
st[i]=true;
dfs(u+1);
st[i]=false;
path.pop_back();
}
}
}
int main()
{
cin>>n;
dfs(0);
return 0;
}
- フィボナッチシーケンス(マスター)の
問題については何も言うことはなく、通常の再帰です。
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main()
{
int n;
cin>>n;
if(n==1)
{
cout<<"0"<<endl;
}
else
{
a[0]=0;
a[1]=1;
cout<<"0"<<" "<<"1"<<" ";
for(int i=2;i<=n-1;i++)
{
a[i]=a[i-1]+a[i-2];
cout<<a[i]<<" ";
}
cout<<endl;
}
return 0;
}
- 不可解なスイッチ(理解してみてください)
この質問の核となるアイデアは次のとおりです:
まず第一に、各グリッドは実際にはクリックするだけで済みます偶数を押しても効果はありません奇数を押した場合は偶数+1と同等であり、これはを押すのと同じです。最小ステップの原則に準拠していません。
同時に、バルブのオン/オフはバイナリで0/1に相当し、ビット操作でライトのオン/オフを制御できます。
//首先每个格子都只能按一下,如果按偶数下那么没有效果,如果按技术下,又和1下相同,不符合最小步数原理
#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};
int dy[5]={
0,1,0,-1,0};
void turn(int x,int y)
{
for(int i=0;i<5;i++)
{
int a=x+dx[i];
int b=y+dy[i];//二进制48 49 分别为110000,110001,只差1,所以可以亦或
if(a<0||a>=5||b<0||b>=5)
{
continue;}
g[a][b]^=1;
}//由于字符型0的asicii值为48,1的为49,亦或即便为对位上的相反的数,所以只有最后一位对位相反
}
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++)//第一行可以变成32种可能性,依据按与不按分为32种情况,设1为可以0为不可以
{
//例如10001为操作第一位和最后一位
memcpy(backup,g,sizeof g);
int step=0;
for(int i=0;i<5;i++)
{
if(op>>i&1)//二进制位运算,代表着如果op的二进制数中为0则不操作,为1则可操作(选或不选问题)
{
//所以对5位二进制数的每一位枚举只要有一就改变
step++;
turn(0,i);//改变原有的亮光程度
}
}
for(int i=0;i<4;i++)//一次枚举剩下的4x5
{
for(int j=0;j<5;j++)
{
if(g[i][j]=='0')
{
step++;
turn(i+1,j);//下面决定上面,当上面有0的时候,摁下面
}
}
}
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)
{
cout<<"-1"<<endl;
}
else
{
cout<<res<<endl;
}
}
return 0;
}