最小步数(图论建模)
第2题 最小步数 查看测评数据信息
小明来到了一个矩形迷官,每个房间写着一个数字。小明初始在左上角的房间,她准备前往该迷言的右下角房间,每次小明可以向右或者向下行走一步。另外,小明可以进行若干次传送,每次可以花费1的步数,前往和当前房间不互素的任意一个房间。现在,小明希望你求出从左上角走到右下角的最小步数。你能帮帮她吗?
输入格式
第一行两个整数n,m,表示迷宫有n行m列
接下来n行,每行m个数,a[i][j],表示每个房间的数字
1<=n,m<=500,1<=a[i][j]<=1e5
输出格式
一个整数
输入/输出例子1
输入:
3 3
1 2 3
2 3 3
3 4 5
输出:
3
样例解释
第一步,向右走一步,当前格子为2.
第二步,传送到第三行第二列的4.
第三步,向右走一步。
还是考的建模,要如何抽象的变成图论,建图
首先看到,如果暴力做,连每个点到每个点的边,是O(n^4)的,预处理的时候就炸了
所以我们还是,建立虚拟点!以节省复杂度
但是我们发现,只要两个点能连边,就是不互素,也就是至少有一个公共因数
但是因数比较多,我们可以考虑质因数。
因为质因数最对只需要最多遍历6个,就可以找完了。
我们分解质因数:
2 3 5 7 11 13
2*3*5*7*11*13>=1e5
一个数,如果有一个质因数,就和这个质因数点双向连边,这样就确保了“传送”功能
注意边权设置1,因为你要实现“传送”功能,就需要从这个点到质因数点,然后再从质因数点到别的点,要一来一回,花费边权就是2,具体为什么看下文。
然后点和别的点(向下,右扩展的点)连的的边权也是2,这样总体答案除2就行。
或者另外一种方法:
对于一个点x
x->质因数点边权为1,质因数点->x边权为0
注意一下,要预处理每个数的质因数,不然在循环里面去找会炸。卡在这里好久。。
#include <bits/stdc++.h>
using namespace std;
const int N=600;
struct node
{
int v, w;
bool operator <(const node &A) const
{
return w>A.w;
};
};
int n, m, c[N][N], vis2[N*N], zhi[N], cnt=0;
int dx[]={0, 1}, dy[]={1, 0};
int dis[N*N], vis[N*N];
vector<node> a[N*N];
vector<int> v[N][N];
priority_queue<node> q;
void dij()
{
memset(dis, 63, sizeof dis);
memset(vis, 0, sizeof vis);
dis[1*501+1]=0;
q.push({1*501+1, 0});
while (!q.empty())
{
int u=q.top().v;
q.pop();
if (vis[u]) continue;
vis[u]=1;
for (int i=0; i<a[u].size(); i++)
{
int v=a[u][i].v, w=a[u][i].w;
if (dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
q.push({v, dis[v]});
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++) scanf("%d", &c[i][j]);
vis2[1]=1;
for (int i=2; i*i<=350; i++)
if (!vis2[i])
for (int j=i*i; j<=350; j+=i)
vis2[j]=1;
for (int i=2; i<=350; i++) if (!vis2[i]) zhi[++cnt]=i;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
for (int k=1; k<=cnt && zhi[k]*zhi[k]<=c[i][j]; k++)
if (c[i][j]%zhi[k]==0)
{
int t=c[i][j]/zhi[k];
v[i][j].push_back(zhi[k]);
if (zhi[k]!=t && !vis2[t]) v[i][j].push_back(t);
}
if (!vis2[c[i][j]]) v[i][j].push_back(c[i][j]);
}
/*
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
printf("[%d, %d] : ", i, j);
for (int k=0; k<v[i][j].size(); k++)
printf("%d ", v[i][j][k]);
puts("");
}
*/
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
for (int k=0; k<v[i][j].size(); k++)
{
a[i*501+j].push_back({v[i][j][k]+260000, 1});
a[v[i][j][k]+260000].push_back({i*501+j, 1});
}
for (int k=0; k<2; k++)
{
int nx=i+dx[k], ny=j+dy[k];
if (nx>=1 && nx<=n && ny>=1 && ny<=m)
{
a[i*501+j].push_back({nx*501+ny, 2});
a[nx*501+ny].push_back({i*501+j, 2});
}
}
}
dij();
printf("%d", dis[n*501+m]/2);
return 0;
}

浙公网安备 33010602011771号