题意:
给定数字n,m,(1≤n,m≤500000)
将n变为n*2的花费为2,将n变为n-3的花费为3,要求过程当中所有数字都在[1,500000]区间内。
求将n变为m的最少花费。
思路:
将每个数字视为图论中的点,数字之间的转换视为图论中的边。有向图!
500000个点,连边(i,i*2)权值为2,连边(i,i-3)权值为3
求n至m的最短路就是最小花费
除Floyd之外的方法,时间复杂度均符合要求
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int inf = 99999999;
const int maxn = 500000 + 5;
struct edge {
int v, w;
};
vector<vector<edge>>a;
vector<int>dis(maxn, inf);
vector<bool>flag(maxn, false);
void add_edge(int u,int v,int w) {
edge tmp;
tmp.v = v;
tmp.w = w;
a[u].push_back(tmp);
}
bool legal(int x) { return x > 0 && x <= 500000; }
void spfa(int s) {
queue<int>q;
q.push(s);
dis[s] = 0;flag[s] = true;
while (!q.empty()) {
int u = q.front(); q.pop(); flag[u] = false;
for (int i = 0; i < a[u].size(); i++) {//扫描所有邻接点
if (dis[a[u][i].v] > dis[u] + a[u][i].w) {
dis[a[u][i].v] = dis[u] + a[u][i].w;
if (!flag[a[u][i].v]) {
q.push(a[u][i].v);
flag[a[u][i].v] = true;
}
}
}
}
}
int main() {
int s, t;
scanf("%d%d", &s, &t);
a.resize(maxn);
for (int i = 1; i <= maxn; i++) {
if (legal(i * 2)) add_edge(i, i * 2, 2);
if (legal(i - 3)) add_edge(i, i - 3, 3);
}
spfa(s);
if (dis[t] != inf)printf("%d\n", dis[t]);
else printf("-1\n");
return 0;
}