第二次双周赛

7-1 输出全排列

题目描述

请添加图片描述

解题方法

简单的全排列问题,只需要使用简单的深搜,细节上注意回溯,则能促使每次输出为规定顺序的全排列。

解题代码

#include<iostream>
using namespace std;
int n;
int vis[20]={0};
int a[20]={0};
void dfs(int cnt)
{
	if(cnt==n)//如果使用数字的个数到达n,则输出此排列
	{
		for(int j=1;j<=n;j++)
		{
			cout<<a[j];
		}
		cout<<endl;return;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]!=1)
		{
			vis[i]=1;//标记此数字已经使用过
			cnt++;//使用数字个数+1
			a[cnt]=i;//标记此位置的数字
			dfs(cnt);
			cnt--;//以下回溯
			vis[i]=0;
		}
	}
	return;
}
int main()
{
	cin>>n;
	dfs(0);
	return 0;
}

7-2 山

题目描述

请添加图片描述

解题方法

阅读完本题,明确此题为类似连通图的问题,但不是图的问题,只需要从每个点位进行搜索,在每个封闭区域经过时标记为已经过,每次能开始dfs深搜时计数器加一,就能判断有多少个连通图,得出的便是答案

解题代码

#include<iostream>
#include<cstring>
using namespace std;
int n,m,ans=0;
int vis[2020][2020],map[2020][2020];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void dfs(int x,int y)
{
	vis[x][y]=1;//标记为经过
	for(int i=0;i<4;i++)//向四周搜索
	{
		int tx=x+dx[i];
		int ty=y+dy[i];
		if(tx<=0||tx>n||ty<=0||ty>m) continue;//判断越界
		if(vis[tx][ty]!=1&&map[tx][ty]==1)
		{
			dfs(tx,ty);
		}
	}
	return;
}
int main()
{
	memset(vis,0,sizeof(vis));
	memset(map,-1,sizeof(map));
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>map[i][j];
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(vis[i][j]==1) continue;//如果已经过此点位,则跳过
			if(map[i][j]==1)
			{
				ans++;//计数器+1
				dfs(i,j);//从此点位开始搜索
			}
		}
	}
	cout<<ans;
	return 0;
}

7-3 跳跃

题目描述

请添加图片描述

解题方法

一开始思考时,我想到的时深搜dfs,结果写完提交时发现超时,然后就换成了宽搜bfs。每到一个点位就标记经过,不用考虑什么,因为只要此地方可以到达,就不必计较从哪里来的。就感觉是简单的bfs模板题目,直接套模板就能过。

解题代码

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int n,flag=0;
int vis[60010],m[60010];
queue<int>q;
void bfs(int x)
{
	q.push(x);
	vis[x]=1;
	while(!q.empty())//套bfs模板
	{
		int dd=q.front();//取头元素
		q.pop();//出队
		vis[dd]=1;
		if(m[dd]==0)
		{
			flag=1;break;
		}
		int di=dd+m[dd];
		if(di<n&&vis[di]==0)
		{
			q.push(di);//入队
		}
		int dj=dd-m[dd];
		if(dj>=0&&vis[dj]==0)
		{
			q.push(dj);//同理
		}
	}
	return;
}
int main()
{
	int st;
	memset(vis,0,sizeof(vis));
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>m[i];
	}
	cin>>st;
	if(m[st]==0)//特殊条件
	{
		cout<<"True";return 0;
	}
	bfs(st);
	if(flag) cout<<"True";//flag标记是否到达出口
	else cout<<"False";
	return 0;
}

7-4 最长光路

题目描述

请添加图片描述
请添加图片描述
请添加图片描述

解题方法

此问题很明显是dfs的运用,但是多了个光路的判断条件,那就按照题目的说法,规划dfs的写法。

在dfs向四周方向出发,每一条路线都要搜索一遍,然后在dfs里,增加遇到反射的情况的判断条件,然后变换方向,继续搜索。

遇到回路,则判断此方向的路线是否经过此位置,则一定为回路。

解题代码

#include<iostream>
#include<cstring>
using namespace std;
int n,m,len,ans=0;
int vis[505][505][4]={0};
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};//方向x和y要统一
char st[4]={'U','R','D','L'};//四个方向
string s[505];
char c;
void dfs(int x,int y,int k)
{
	len++;
	if(vis[x][y][k])//判断此方向的光路是否经过此地方
	{
		len=0x3fffffff;
		return;
	}
	else vis[x][y][k]=1;
	if(s[x][y]=='\\')//光路反射
	{
		if(st[k]=='D') k--;
		else if(st[k]=='R') k++;
		else if(st[k]=='U') k=3;
		else if(st[k]=='L') k=0;
	}
	if(s[x][y]=='/')//同理
	{
		if(st[k]=='D') k++;
		else if(st[k]=='R') k--;
		else if(st[k]=='U') k++;
		else if(st[k]=='L') k--;
	}
	int xx=x+dx[k],yy=y+dy[k];
	if(xx<0||yy<0||xx>=n||yy>=m||s[xx][yy]=='C') return;//判断越界
	dfs(xx,yy,k);//往此方向继续搜索
	return;
}
int main()
{
	int tx,ty;
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
	}
	cin>>tx>>ty;
	tx--;ty--;//数组下标从0开始
	for(int i=0;i<4;i++)//四个方向搜索
	{
		memset(vis,0,sizeof(vis));
		len=0;
		dfs(tx,ty,i);
		if(len>ans)
		{
			c=st[i];
			ans=len;
		}
	}
	cout<<c<<endl;
	if(ans<0x3fffffff) cout<<ans<<endl;
	else cout<<"COOL"<<endl;
	return 0;
}

7-5 回文数文回

题目描述

请添加图片描述

解题方法

因为此问题为回文数,可以把范围里的数直接分成两部分,一部分和另一部分一定要一样才能形成回文数。

所以直接在一部分进行每一位数枚举,另一部分反转复制,然后两部分合起来是否符合范围,那就是答案。

此为暴力枚举。

解题代码

#include<iostream>
#include<cstring>
using namespace std;
int n,ans=0,sum=0;
int a[15];
int main()
{
	memset(a,0,sizeof(a));
	cin>>n;
	for(int i=1;i<=9;i++)//五个循环暴力枚举
	{
		sum=0;
		a[1]=a[9]=i;
		sum+=a[1]*100000000;
		sum+=a[9]*1;
		for(int j=0;j<=9;j++)
		{
			a[2]=a[8]=j;
			sum+=a[2]*10000000;
			sum+=a[8]*10;
			for(int k=0;k<=9;k++)
			{
				a[3]=a[7]=k;
				sum+=a[3]*1000000;
				sum+=a[7]*100;
				for(int q=0;q<=9;q++)
				{
					a[4]=a[6]=q;
					sum+=a[4]*100000;
					sum+=a[6]*1000;
					for(int w=0;w<=9;w++)
					{
						a[5]=w;
						sum+=a[5]*10000;
						if(sum<=n) ans++;//判断是否小于最大范围
						sum-=a[5]*10000;
					}
					sum-=a[4]*100000;
					sum-=a[6]*1000;
				}
				sum-=a[3]*1000000;
				sum-=a[7]*100;
			}
			sum-=a[2]*10000000;
			sum-=a[8]*10;
		}
		sum-=a[1]*100000000;
		sum-=a[9]*1;
	}
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值