搜索算法 – Wasting_Misaka.Blog https://forelink.top Hso! Mon, 12 Dec 2022 10:36:48 +0000 zh-Hans hourly 1 https://wordpress.org/?v=6.7.1 第二次双周赛。 https://forelink.top/index.php/2022/12/12/%e7%ac%ac%e4%ba%8c%e6%ac%a1%e5%8f%8c%e5%91%a8%e8%b5%9b%e3%80%82/ Mon, 12 Dec 2022 10:36:48 +0000 https://forelink.top/?p=100 T1 输出全排列

是暑假就做过的题!
代码如下。

#include <iostream>
using namespace std;
int n;
int a[11],vis[11];
void dfs(int step){
	if(step==n+1){
		for(int i=1;i<=n;i++){
			cout<<a[i];
		}
		cout<<endl;
		return;
	}
	for(int i=1;i<=n;i++){
		if(vis[i]==0){
			a[step]=i;
			vis[i]=1;
			dfs(step+1);
			vis[i]=0;
		}
	}
	return;
}
int main(){
	cin>>n;
	dfs(1);
	return 0;
}

T2 山

是一道非常经典的搜索题,题中的山可以换成:细胞,海岛(bushi)。
不过我的实现方式比较复杂了!

代码如下。

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
queue<int> x1;
queue<int> y1;
queue<int> tx;
queue<int> ty;
int world[2005][2005];
int color[2005][2005];
int vis[2005][2005];
int n,m;
int ans;
int movex[5]={0,0,0,1,-1};
int movey[5]={0,1,-1,0,0};
int main(){
	memset(world,0x3f,sizeof(world));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int l=1;l<=m;l++){
			cin>>world[i][l];
			if(world[i][l]==1){
				x1.push(i);
				y1.push(l);
			}
		}
	}
	while(!x1.empty()){
		int xx=x1.front();
		int yy=y1.front();
		if(vis[xx][yy]==1){
			x1.pop();
			y1.pop();
			continue;
		}
		vis[xx][yy]=1;
		tx.push(xx);
		ty.push(yy);
		while(!tx.empty()){
			int x2=tx.front();
			int y2=ty.front();
			for(int i=1;i<=4;i++){
				int x3=x2+movex[i];
				int y3=y2+movey[i];
				if(x3>=1&&x3<=n&&y3>=1&&y3<=m&&world[x3][y3]==1&&vis[x3][y3]==0){
					tx.push(x3);
					ty.push(y3);
					vis[x3][y3]=1;
				}
			}
			tx.pop();
			ty.pop();
		}
		ans++;
		x1.pop();
		y1.pop();
	}
	cout<<ans;
}

T3 跳跃

和奇怪的电梯差不多,但是这道题是要找到元素值为0的下标位置。
不用输出步数所以bfs或者dfs都可。(不过我bfs调了超久诶诶诶)

代码如下。

#include <iostream>
#include <queue>
using namespace std;
const int N=5e5+5;
int start,n;
int num[N];
int step[N];
int vis[N];
queue<int> x;
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>num[i];
	}
	cin>>start;
	if(num[start]==0){
		cout<<"True";
		return 0;
	}
	vis[start]=1;

	x.push(start);
	while(!x.empty()){

		int x1=x.front();

		if(num[x1]==0){
			cout<<"True";
			return 0;
		}
		int s=num[x1];
		int l=x1-s;
		int r=x1+s;
		if(l>=0){
			if(vis[l]==0){
				vis[l]=1;
				x.push(l);
			}
		}
		if(r<n){
			if(vis[r]==0){
				vis[r]=1;
				x.push(r);
			}
		}
		x.pop();
	}
	cout<<"False";
	return 0;
}

T4 回文数回文

草,这道题败在了不会估计时间复杂度上面。
从起始数到极限数据回文数并不多,可以枚举。

代码如下。

#include <iostream>
using namespace std;
int ans;
int getnum(int n){
	int temp=n;
	int a[6];
	n/=10;
	for(int i=1;i<=4;i++){
		a[i]=n%10;
		n/=10;
	}
	for(int i=1;i<=4;i++){
		temp*=10;
		temp+=a[i];
	}
	return temp;
}
int main(){
	int a;
	cin>>a;
	for(int i=10000;i<=99999;i++){
		if(getnum(i)<=a){
			ans++;
		}
	}
	cout<<ans;
}

T5 最长光路

这道题怎么一股oi味。(指题面和样例)

代码非常蠢呢 还有一个点过不去www。

#include <iostream>
#include <cstring>
using namespace std;
const int INF=0x3f3f;
//1为上,2为右,3为下,4为左。
//  \可以用\\来表示。
//  \ 1->4 2->3 3->2 4->1

//  / 1->2 2->1 3->4 4->3
char world[505][505];
int vis[505][505][6];
int n,m;
int sx,sy;
int nx,ny;
long long int ans;
char ansdir;
long long int len;
bool check(int x,int y){
	if(x<1||y<1) return 0;
	if(x>n||y>m) return 0;
	if(world[x][y]=='C') return 0;
	return 1;
}
void go(int x,int y,int status){
	if(status==1){
		nx=x-1, ny=y;
	}
	else if(status==2){
		nx=x, ny=y+1;
	}
	else if(status==3){
		nx=x+1, ny=y;
	}
	else if(status==4){
		nx=x, ny=y-1;
	}
}

void dfs(int x,int y,int status){
	++len;
	if(vis[x][y][status]){
		len=INF;
		return;
	}
	else vis[x][y][status]=1;
	if(world[x][y]=='/'){
		if     (status==1) status=2;
		else if(status==2) status=1;
		else if(status==3) status=4;
		else if(status==4) status=3;
	}
	if(world[x][y]=='\\'){
		if     (status==1) status=4;
		else if(status==2) status=3;
		else if(status==3) status=2;
		else if(status==4) status=1;
	}
	go(x,y,status);//更新x和y的值。
	if(!check(nx,ny)) return;
	dfs(nx,ny,status);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int l=1;l<=m;l++){
			cin>>world[i][l];
		}
	}
	cin>>sx>>sy;
	memset(vis,0,sizeof(vis));
	len=0;
	dfs(sx,sy,1);
	if(len>ans) ansdir='U',ans=len;
	
	memset(vis,0,sizeof(vis));
	len=0;
	dfs(sx,sy,2);
	if(len>ans) ansdir='R',ans=len;
	
	memset(vis,0,sizeof(vis));
	len=0;
	dfs(sx,sy,3);
	if(len>ans) ansdir='D',ans=len;
	
	memset(vis,0,sizeof(vis));
	len=0;
	dfs(sx,sy,4);
	if(len>ans) ansdir='L',ans=len;
	
	cout<<ansdir<<endl;
	if(ans!=INF){
		cout<<ans;
	}
	else cout<<"COOL"<<endl;
	return 0;
}

]]>
搜索算法与图论(Week 4 , 5) https://forelink.top/index.php/2022/11/21/%e6%90%9c%e7%b4%a2%e7%ae%97%e6%b3%95%e4%b8%8e%e5%9b%be%e8%ae%ba%ef%bc%88week-4-5%ef%bc%89/ Mon, 21 Nov 2022 12:37:10 +0000 https://forelink.top/?p=94 搜索和动态规划是算法界的两座大山。

搜索本质上是一种遍历,是对每一种情况操作一遍。

T1 迷宫(dfs)

是好题,一道用dfs的好题。

#include <iostream>
#include <cstring>
using namespace std;
int n,m,t;
int movex[5]={0,1,0,-1,0};//右 上
int movey[5]={0,0,-1,0,1};//左 下
int world[15][15];//图
int vis[15][15];//标记
int sx,sy,fx,fy;//起点 终点
int cnt;//计数。
void dfs(int x,int y){
	if(x==fx&&y==fy){
		cnt++;
		return;
	}
	for(int i=1;i<=4;i++){

		int nx=x+movex[i];
		int ny=y+movey[i];
		if(world[nx][ny]==1&&vis[nx][ny]==0){//可以走到。

			vis[nx][ny]=1;
			dfs(nx,ny);
			vis[nx][ny]=0;
		}
	}
}
int main(){
	memset(vis,0,sizeof(vis));
	memset(world,0x3f,sizeof(world));//默认不能走。
	cin>>n>>m>>t;
	for(int i=1;i<=n;i++){
		for(int l=1;l<=m;l++){
			world[i][l]=1;//可以走的。
		}
	}
	cin>>sx>>sy>>fx>>fy;
	for(int i=1;i<=t;i++){
		int x1,y1;
		cin>>x1>>y1;
		world[x1][y1]=0x3f;//障碍。
	}
	vis[sx][sy]=1;
	dfs(sx,sy);
	cout<<cnt;
	return 0;
}

T2 马的遍历

是好题,一道用bfs的好题。

非常愚笨的手写队列。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2e5;
struct note{
	int x;//横坐标。
	int y;//纵坐标。
	int step;//步数。
};
note point[N];
int movex[9]={0,2, 2, 1, 1,-1,-1,-2,-2};
int movey[9]={0,1,-1, 2,-2, 2,-2, 1,-1};
int world[405][405];
int step[405][405];
bool vis[405][405];
int n,m;
int mx,my;
int main(){
	memset(world,0x3f,sizeof(world));//
	memset(step,0,sizeof(step));//特判
	cin>>n>>m;//输入N M。
	cin>>mx>>my;//输入起点。
	for(int i=1;i<=n;i++){
		for(int l=1;l<=m;l++){
			world[i][l]=1;//能走的点。
		}
	}
	//step前+1 = step后。
	int head=1,tail=1;
	point[head].x = mx;
	point[head].y = my;//起点??
	vis[mx][my]=true;
	tail++;
	while(head<tail){
                        for(int i=1;i<=8;i++){
			int cur_x=point[head].x+movex[i];//移动后的横坐标。
			int cur_y=point[head].y+movey[i];//移动后的纵坐标。

			if(cur_x<=0||cur_y<=0) continue;//防止数组越界。
			if(world[cur_x][cur_y]==1&&vis[cur_x][cur_y]==false){//可以走 且 没走过。

				point[tail].x=cur_x;//记录横坐标。
				point[tail].y=cur_y;//记录纵坐标。
				vis[cur_x][cur_y]=true;//这个点已经走过了。
				step[cur_x][cur_y]=step[point[head].x][point[head].y]+1;//从开始遍历八个方向的点的STEP+1。
				tail++;//记录 入列。
//cout<<"step head: "<<step[point[head].x][point[head].y]<<endl;
//cout<<"step cur : "<<step[cur_x][cur_y]<<endl<<endl;
			}
		}
		head++;//遍历完成。
	}
	for(int i=1;i<=n;i++){
		for(int l=1;l<=m;l++){
			if(step[i][l]==0){
				step[i][l]=-1;//仍然为0的点。
			}
		}
	}
	step[mx][my]=0;//起点为0。
	
	for(int i=1;i<=n;i++){
		for(int l=1;l<=m;l++){
			cout<<step[i][l]<<"    ";
		}
		cout<<endl;
	}
	return 0;
}

待续…………。

]]>