spfa--模板

题意:
给定数字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;
}

猜你喜欢

转载自blog.csdn.net/qq_38995588/article/details/80620936