Revisit recursive and search

Update records

[1]2020.05.16-11:02

1. Improve the content

text

Tips before observation

  1. This article is a review series, not very detailed
  2. Need to have some recursive recursion and search basis

Recurrence

preface

Although it is recursive, it is closely related to dynamic planning
(my dynamic planning can't even reach the level of popularization)
So, recursion is the simplest thing, but it's also the most difficult thing for beginners to understand

Why is it simple?

  • Take this algorithm alone, and you will find that you can't say anything

Why is it hard to understand?

  • When you combine it into a question, sometimes you will find that you can't even figure out your ideas

So let's talk about the topic here

Fibonacci series

Orientation: basic question / entry difficulty

Of course, I'm referring to the naked question here (your FFT + Fibonacci numbers list the big problems)
\(f[i]=f[i-1]+f[i-2]\)

Notice the boundary conditions
And then it's gone

There's nothing to say. Notice that \ (i-1 \) and \ (i-2 \) have been evaluated. Just think of using array to store them

#include<iostream>
using namespace std;
int a[1000100],num=0,in;
int main(){
	a[1]=1;a[2]=1;cin>>num;
	for(int i=3;i<1000002;i++)
		a[i]=(a[i-1]+a[i-2])
	for(int i=0;i<num;i++){
		cin>>in;cout<<a[in]<<"\n";
	}
}

Digit problem

Orientation: basic questions / Popularization - difficulty

This problem is still very simple to do, but the process is a little testing everyone

Among the two digits, those with odd number 3 are:
\(13,23,43,53,63,73,83,93\)
\(30,31,32,34,35,36,37,38,39\)

Then we observe that when 3 is not in the highest position, the quantity is multiplied by 8

  • High order cannot be 0 or 3

Number multiplied by 9 at the highest level

  • It can be 0 but not 3 when it is not the highest position

And so on, the number of odd 3 numbers in three digits is:

  • Individual bit
    \((103,113,123,143,153,163,173,183,193)\)
    Total 9 × 8 = 72

  • Ten
    \((130,131,132,134,135,136,137,138,139)\)
    Total 9 × 8 = 72

  • Centenary
    \((301,302,304,305,306...398,399)\)
    100-9-9 = 81 in total

  • other
    \((333)\)
    1 in total

So the number of odd number 3 is 72 × 2 + 81 + 1 = 226

Define array \ (f[i][2] \):

  • \(f[i][0] \) indicates the number of even 3 digits in the i-digit
  • \(f[i][1] \) indicates the number of odd 3 digits in the i-digit

The dynamic transfer equation is:
\(f[i][0]=(f[i-1][0]*9+f[i-1][1])%12345\)
\(f[i][1]=(f[i-1][1]*9+f[i-1][0])%12345\)

Just multiply the highest order by 8

#include<iostream>
using namespace std;
int f[20001][2],n;
int main(){
	cin>>n;f[1][0]=9;f[1][1]=1;
	for(int i=2;i<n;i++){
		f[i][0]=(f[i-1][0]*9+f[i-1][1])%12345;
		f[i][1]=(f[i-1][1]*9+f[i-1][0])%12345;
	}
	if(n!=1){
		f[n][0]=f[n-1][0]*8+f[n-1][1];
		f[n][1]=f[n-1][1]*8+f[n-1][0];
	}
	cout<<f[n][0]%12345;
}

Step on the grid

Orientation: exercises / popularization difficulty

The amount of code in this question is really very small, but it's still hard to think about this idea

A lot of people are confused that they can't walk again
But we just need to sweep in separate directions

Define \ (f[i][3] \)

  • \(f[i][0] \) means step I goes up
  • \(f[i][1] \) means step I goes to the left
  • \(f[i][2] \) means step I goes to the right
#include<iostream>
using namespace std;
int n,f[25][3];
int main(){
	cin>>n;f[1][0]=1;f[1][1]=1;f[1][2]=1;
	for(int i=2;i<=n;i++){
		f[i][0]=f[i-1][0]+f[i-1][1]+f[i-1][2];
		f[i][1]=f[i-1][0]+f[i-1][1];
		f[i][2]=f[i-1][0]+f[i-1][2];
	}
	cout<<f[n][0]+f[n][1]+f[n][2];
//In the end, that's the answer
}

Building primary schools in Mountainous Areas

Orientation: think / improve difficulty

This problem is relatively comprehensive. In terms of the dynamic rules, there are few codes but it is difficult to come up with them

Define \ (b[i][o] \) and \ (f[i][o] \)
\(b[i][o] \) indicates the distance from I to o if a primary school is built, I to all villages in o to this primary school, and
\(f[i][o] \) represents the optimal solution for the first I villages to build o primary schools

#include<iostream>
#include<cmath>
using namespace std;
int n,m,a[501],mid,i,o,p;
int b[501][501],f[501][501];
int main(){
	cin>>n>>m;
	for(i=2;i<=n;i++){
		cin>>a[i];a[i]+=a[i-1];
	}
//Here we use prefix sum to find the distance between two points
	for(i=1;i<=n;i++){
		for(o=i;o<=n;o++){
			mid=(i+o)/2;
			for(p=i;p<=o;p++)
				b[i][o]+=abs(a[mid]-a[p]);
		}
	}
//Obviously, the midpoint between two points must be the minimum value of b[i][o]
	for(int i=0;i<=n;i++){
		for(int o=0;o<=m;o++)
			f[i][o]=99999999;
	}
//initialization
	f[0][0]=0;
	for(i=1;i<=n;i++){
		for(o=1;o<=m;o++){
			if(o>i){
				f[i][o]=0;continue;
			}
//There are more schools to be built than villages = > there are primary schools at the gate of each village = > the sum of distances is zero
			for(p=o-1;p<i;p++)
				f[i][o]=min(f[i][o],f[p][o-1]+b[p+1][i]);
//Enumeration of the first i villages
		}
	}
	cout<<f[n][m];
//output
}

recursion

In fact, recursion can be understood as another way of writing dynamic rules (it's only slower, it takes up more memory)

Count of numbers

Orientation: basic questions / Popularization - difficulty

This question is a (anti recursion) send experience question

Recursion idea: start from 1 on the left and add to n/2
Recursion of next step after adding

Recursion version timeout 1 ms

#include<cstdio>
int n,num=1;
inline void pan(int n){
	for(int i=1;i<=(n>>1);++i){
		num+=1;pan(i);
	}
}
int main(){
	scanf("%d",&n);
	pan(n);
	printf("%d",num);
}

Overtime is not very good, so we change it into a dynamic gauge
Sweep from 1 to n

Little proof:

  • n the left side can only add a number smaller than half
  • But the added number (because it's smaller than n) has been calculated before
  • Just add it directly
  • Pay attention to boundary conditions

It's the perfect AC when changing into a dynamic gauge

#include<iostream>
using namespace std;
long long int f[1002];int a;
int main()
{
	f[1]=1;
	for(int i=2;i<=1001;i++){
		for(int o=1;o<=i/2;o++)
			f[i]+=f[o];
		f[i]+=1;
	}
	cin>>a;cout<<f[a];
}

So if you can still use it, use it. Recursive TLE and MLE will make you unable to play

search

(the greatest contribution of this algorithm is to prove that recursion is not useless.)

Generally speaking, we will encounter many different situations at a decision-making point
There will be many different situations after choosing one
But there are boundaries and decision points are limited

Then violent recursion -- search algorithm appears!!

Search is to go through everything
But time and memory will be very high

Sometimes, a series of metaphysical operations such as backtracking, pruning (interval dynamic gauge) are used

Horse walking day

Orientation: basic questions / popularization difficulty

There's nothing to say. Every step of expansion is enough

#include<iostream>
using namespace std;
int t,n,m,x,y,num;
bool bl[101][101];
int sx[8]={2,1,-1,-2,2,1,-1,-2};
int sy[8]={1,2,2,1,-1,-2,-2,-1};
void pan(int x,int y,int s){
	if(x<0||y<0||x>=n||y>=m) return;
	if(s==n*m) num+=1;
	bl[x][y]=1;
//This point has been temporarily marked for use in the next step
	for(int i=0;i<8;i++)
		if(!bl[x+sx[i]][y+sy[i]])
			pan(x+sx[i],y+sy[i],s+1);
//Core, expanding in 8 directions
	bl[x][y]=0;
//This step is over. The mark is not used
}
int main(){
	cin>>t;
	for(int i=0;i<t;i++){
		num=0;cin>>n>>m>>x>>y;
		pan(x,y,1);cout<<num<<"\n";
	}
}

Word Chain

Orientation: exercises / popularization difficulty

To sort out the questions:

  • Use a word twice at most

  • Not all the words

  • Cannot contain

  • There should be as little overlap as possible

So it is a function to judge the length of overlapping parts
Just search once

#include<iostream>
using namespace std;
string a[50];
int n,cnt[50],num,maxn;
char begin;
int yn(int a,int b){
	int ayn=1,al=(::a[a].length());
	for(int i=al-1;i>=0;i--){
		ayn=1;
		if((::a[a][i])==(::a[b][0])){
			for(int o=i;o<al;o++){
				if((::a[a][o])!=(::a[b][o-i])){
					ayn=0;break;
				}
			}
			if(ayn)
				return al-i;
		}
	}
	return 0;
}
void fs(int wei,int l,int p){
	if(l>maxn)
		maxn=l;
	for(int i=0;i<n;i++){
		if(cnt[i]>=2) continue;
		int c=yn(wei,i);
		if(c&&(c!=a[wei].length()||c!=a[i].length())){
			cnt[i]+=1;fs(i,l+a[i].length()-c,p+1);cnt[i]-=1;
		}
		
	}
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>a[i];
	cin>>begin;
	for(int i=0;i<n;i++){
		if(a[i][0]==begin){
			cnt[i]+=1;fs(i,a[i].length(),1);cnt[i]-=1;
		}
	}
	cout<<maxn;
}

summary

  • These three algorithms are related to each other and pay attention to balance during learning

Posted on Sun, 17 May 2020 05:28:26 -0400 by fussy