试题 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;
}