15届蓝桥杯省赛(E,F...) 较难部分题解

试题 F: 数字接龙

#include <bits/stdc++.h>  
using namespace std;  
  
// 地图大小  
int n, k, got;  
// 标记是否已经访问过  
int vis[20][20], face[20][20], mp[20][20]; // face用于储存朝向,mp为地图上的数字  
  
// 八个方向的向量  
int vec[20][2] = {  
    {-1,0},{-1,1},{0,1},{1,1},  
    {1,0},{1,-1},{0,-1},{-1,-1},  
};  
vector<int> ans; // 储存答案路径 
  
// 检查坐标是否在地图范围内  
bool check(int x, int y){  
    if( x < 1 || x > n || y < 1 || y > n)  
        return false;  
    return true;  
}  
  
// 深度优先搜索函数  
void dfs(int x, int y, int res){  
    if (got) // 如果已经找到解,则直接返回  
        return;  
      
    if(res == 0 && x == n && y == n) { // 如果步数恰好用完,且到达目标点(n,n)  
        got = 1;  
        return;  
    }  
      
    for( int i = 0 ; i < 8 ; i++){  
        int tx = x + vec[i][0];  
        int ty = y + vec[i][1];  
          
        if(!check(tx, ty)) continue; // 如果坐标超出范围,则跳过  
          
        if(vis[tx][ty]) // 如果已经访问过该点,则跳过  
            continue;  
              
        // 根据当前点和目标点的数字进行路径判断  
        if(mp[x][y] == k - 1) { // 如果当前点是起点  
            if(mp[tx][ty] != 0) // 如果下一个点不是空白,则跳过  
                continue;  
        }   
        else {  
            if (mp[x][y] + 1 != mp[tx][ty]) // 如果下一个点的数字不是当前点数字+1,则跳过  
                continue;  
        }  
          
        // 判断是否会与之前的路径交叉  
        // 这里只检查了四个方向(1, 3, 5, 7),其他方向类似  
        if (i == 1) { // 朝向为右上方  
            // 检查左方和上方是否有朝向相反的路径  
            int mx1 = x - 1;  
            int my1 = y;  
            if(check(mx1, my1) && face[mx1][my1] == 3) // 3为左下方的朝向  
                continue;  
                  
            int mx2 = x;  
            int my2 = y + 1;  
            if(check(mx2, my2) && face[mx2][my2] == 7) // 7为右上方的朝向  
                continue;  
        }  
        // ... 其他方向的判断类似 ...  
        else if ( i == 3 ){
			int mx1 = x;
			int my1 = y + 1;
			if(check(mx1, my1) && face[mx1][my1] == 5)
				continue;
				
			int mx2 = x + 1;
			int my2 = y;
			if(check(mx2, my2) && face[mx2][my2] == 1)
				continue;
				
		} else if ( i == 5 ){
			int mx1 = x;
			int my1 = y - 1;
			if(check(mx1, my1) && face[mx1][my1] == 3)
				continue;
				
			int mx2 = x + 1;
			int my2 = y;
			if(check(mx2, my2) && face[mx2][my2] == 7)
				continue;
				
		} else if ( i == 7 ){
			int mx1 = x - 1;
			int my1 = y;
			if(check(mx1, my1) && face[mx1][my1] == 5)
				continue;
				
			int mx2 = x;
			int my2 = y - 1;
			if(check(mx2, my2) && face[mx2][my2] == 1)
				continue;
		}
        // 标记为已访问,并设置朝向,加入答案路径  
        vis[tx][ty] = 1;  
        face[x][y] = i;  
        ans.push_back(i);  
          
        // 递归搜索下一个点  
        dfs(tx, ty, res - 1);  
          
        // 如果递归回来没有找到解,则回溯  
        if(!got) {  
            vis[tx][ty] = 0;  
            face[x][y] = -1;  
            ans.pop_back();  
        }  
    }  
}
int main() {
	
	
	cin >> n >> k;
	
	for(int i = 1 ; i <= n ; i++)
		for(int j = 1 ; j <= n ; j++)
			cin >> mp[i][j], face[i][j] = -1;
	
	vis[1][1] = 1;
	dfs(1, 1 , n * n - 1);//从(1,1)开始,还要走n^2-1步 
	
	if(got)
		for(auto v : ans)
			cout << v ;
	else 
		cout << -1; 
	return 0;
}

试题 E: 宝石组合

三重循环暴力枚举自然不必多说,过60%都够呛,那么怎么优化呢?

看到这个等式,是不是很想约分呢?

那么就要知道 lcm(a,b,c)=?

根据互不相容原则

于此同时我们知道 LCM ( a , b ) = a * b / gcd ( a , b )

此时此刻,我们可以得到 S = gcd ( a , b , c )

选3个数公因子最大,可以理解为,当处理完所有数的因子,因子从大到小个数是三及以上的,就一定是最大可得到的S

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+3;
const int M=sqrt(N)+3;
int h[N];
vector <int> v[N];//v[i][j]对应i这个因素,是j提供的 
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>h[i]; 
	} 
	sort(h+1,h+n+1);//对序列排序,确保v[i][j]中j是从小到大排列 
	//处理每一个数的因子个数
	for(int i=1;i<=n;i++){
		for(int j=1;j<=sqrt(h[i]);j++)
		{
			int t=h[i]%j;
			if(t==0)
			{
				v[j].push_back(h[i]);//j这个因子由h[i]提供 
				if(j!=sqrt(h[i])) //h[i]还提供了h[i]/j这个因子 
					v[h[i]/j].push_back(h[i]);
			} 
		} 
	}	
	int pos=0;//找出符合条件的因子 
	for(int i=N;i>=1;i--)
	{
		if(v[i].size()>=3)
		{
			pos=i;
			break;
		}
	} 
	//输出前三个 
	for(int i=0;i<=2;i++)
	{
		cout<<v[pos][i]<<' ';
	}
	return 0;	
} 
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值