SCUT - 486 - 无向图上的点 - Dijkstra
好像原题是这个?https://www.cnblogs.com/kanchuang/p/11120052.html
这个有解释:https://blog.csdn.net/wddwjlss/article/details/82081754
原题是这个:https://www.luogu.org/problem/P1144
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e5 + 3, MAXN = 1e6 + 5;
const int INF = 1e9;
vector<int> e[MAXN];
inline void add_edge(int u, int v) {
e[u].emplace_back(v);
e[v].emplace_back(u);
}
bool vis[MAXN];
int dis[MAXN], ans[MAXN];
priority_queue<pair<int, int> > pq;
void Dijkstra(int n, int s) {
for(int i = 1; i <= n; i++)
dis[i] = INF;
dis[s] = 0, ans[s] = 1, pq.push({0, s});
while(!pq.empty()) {
int u = pq.top().second;
pq.pop();
if(vis[u])
continue;
vis[u] = 1;
for(auto v : e[u]) {
if(!vis[v] && dis[v] > dis[u] + 1) {
dis[v] = dis[u] + 1;
ans[v] = ans[u];
pq.push({-dis[v], v});
} else if(!vis[v] && dis[v] == dis[u] + 1) {
ans[v] = (ans[v] + ans[u]) % MOD;
}
}
}
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
add_edge(u, v);
}
Dijkstra(n, 1);
for(int i = 1; i <= n; ++i)
printf("%d\n", ans[i]);
}
询问从1节点开始的最短路的种类数。
首先连接两个点之间的不是最短的路一定是没有用的。所以至多每种d就n/d条边,同样的直接叠加条数,计数时乘法叠加路径数。
在dijkstra的同时,要是更新了就清空,否则相等就继续计数。
图论知识太缺乏。
哈哈哈我居然能过!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e4 + 5;
const int MAXM = 1400000 + 5;
struct Edge {
int v, w, k, next;
Edge(int v = 0, int w = 0, int k = 0): v(v), w(w), k(k) {}
};
int cnt_edge;
int head[MAXN];
Edge edge[MAXM];
inline void init_graph(int n) {
cnt_edge = 0;
memset(head + 1, 0, sizeof(head[0])*n);
}
inline void add_edge(int u, int v, int w, int k) {
cnt_edge++;
edge[cnt_edge].v = v;
edge[cnt_edge].w = w;
edge[cnt_edge].k = k;
edge[cnt_edge].next = head[u];
head[u] = cnt_edge;
}
bool vis[MAXN];
int dis[MAXN];
int ans[MAXN];
struct Edge_node {
int v, w;
Edge_node(int v = 0, int w = 0): v(v), w(w) {}
bool operator<(const Edge_node &e)const {
return w > e.w;
}
};
const int MOD = 1e9 + 9;
void Dijkstra(int n, int s) {
memset(vis + 1, 0, sizeof(vis[0])*n);
for(int i = 1; i <= n; i++)
dis[i] = INF;
priority_queue<Edge_node> pq;
dis[s] = 0;
ans[s] = 1;
pq.push(Edge_node(s, 0));
while(!pq.empty()) {
int u = pq.top().v;
pq.pop();
if(vis[u])
continue;
vis[u] = 1;
for(int i = head[u]; i; i = edge[i].next) {
int &v = edge[i].v;
int &w = edge[i].w;
if(!vis[v] && dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
ans[v] = 1ll * ans[u] * edge[i].k % MOD;
pq.push(Edge_node(v, dis[v]));
} else if(!vis[v] && dis[v] == dis[u] + w) {
ans[v] = (ans[v] + 1ll * ans[u] * edge[i].k % MOD) % MOD;
}
}
}
}
int minw[MAXN];
int minw2[MAXN];
int dk[MAXN];
int dk2[MAXN];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= m; i++) {
int d, v, w;
scanf("%d%d%d", &d, &v, &w);
if(v == 1) {
if(minw[d] == 0 || minw[d] > w) {
minw[d] = w;
dk[d] = 1;
} else if(minw[d] == w) {
++dk[d];
}
} else {
if(minw2[d] == 0 || minw2[d] > w) {
minw2[d] = w;
dk2[d] = 1;
} else if(minw2[d] == w) {
++dk2[d];
}
}
}
init_graph(n);
for(int d = 1; d <= n; d++) {
if(minw[d]) {
for(int v = 1; v <= n; v += d) {
if(v + d <= n) {
add_edge(v, v + d, minw[d], dk[d]);
add_edge(v + d, v, minw[d], dk[d]);
}
}
}
}
for(int d = 1; d <= n; d++) {
if(minw2[d]) {
for(int v = n; v >= 1; v -= d) {
if(v - d >= 1) {
add_edge(v - d, v, minw2[d], dk2[d]);
add_edge(v, v - d, minw2[d], dk2[d]);
}
}
}
}
Dijkstra(n, 1);
for(int i = 1; i <= q; ++i) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", ans[y]);
}
}
有点bug,dis应该是ll才对的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 9, MAXN = 5e4 + 5, MAXM = 1400000 + 5;
const ll INF = 1e18;
struct Edge {
int v, w, k, next;
Edge(int v = 0, int w = 0, int k = 0): v(v), w(w), k(k) {}
};
int h[MAXN], etop;
Edge e[MAXM];
inline void init_graph(int n) {
etop = 0;
memset(h + 1, 0, sizeof(h[0])*n);
}
inline void add_edge(int u, int v, int w, int k) {
e[++etop] = Edge(v, w, k);
e[etop].next = h[u];
h[u] = etop;
}
bool vis[MAXN];
ll dis[MAXN];
int ans[MAXN];
priority_queue<pair<ll, int> > pq;
void Dijkstra(int n, int s) {
//vis pq
for(int i = 1; i <= n; i++)
dis[i] = INF;
dis[s] = 0, ans[s] = 1, pq.push({0, s});
while(!pq.empty()) {
int u = pq.top().second;
pq.pop();
if(vis[u])
continue;
vis[u] = 1;
for(int i = h[u]; i; i = e[i].next) {
int &v = e[i].v, &w = e[i].w;
if(!vis[v] && dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
ans[v] = 1ll * ans[u] * e[i].k % MOD;
pq.push({-dis[v], v});
} else if(!vis[v] && dis[v] == dis[u] + w) {
ans[v] = (ans[v] + 1ll * ans[u] * e[i].k % MOD) % MOD;
}
}
}
}
int minw[MAXN], minw2[MAXN], dk[MAXN], dk2[MAXN];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= m; i++) {
int d, v, w;
scanf("%d%d%d", &d, &v, &w);
if(v == 1) {
if(minw[d] == 0 || minw[d] > w) {
minw[d] = w;
dk[d] = 1;
} else if(minw[d] == w)
++dk[d];
} else {
if(minw2[d] == 0 || minw2[d] > w) {
minw2[d] = w;
dk2[d] = 1;
} else if(minw2[d] == w)
++dk2[d];
}
}
init_graph(n);
for(int d = 1; d <= n; d++) {
if(minw[d]) {
for(int v = 1; v <= n; v += d) {
if(v + d <= n) {
add_edge(v, v + d, minw[d], dk[d]);
add_edge(v + d, v, minw[d], dk[d]);
}
}
}
if(minw2[d]) {
for(int v = n; v >= 1; v -= d) {
if(v - d >= 1) {
add_edge(v - d, v, minw2[d], dk2[d]);
add_edge(v, v - d, minw2[d], dk2[d]);
}
}
}
}
Dijkstra(n, 1);
for(int i = 1; i <= q; ++i) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", ans[y]);
}
}
来个vector版的比一比。
感觉差不多,好像vector挺方便的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 9, MAXN = 5e4 + 5;
const ll INF = 1e18;
struct Edge {
int v, w, k;
Edge(int v = 0, int w = 0, int k = 0): v(v), w(w), k(k) {}
};
vector<Edge> e[MAXN];
inline void add_edge(int u, int v, int w, int k) {
e[u].emplace_back(v, w, k);
e[v].emplace_back(u, w, k);
}
bool vis[MAXN];
ll dis[MAXN];
int ans[MAXN];
priority_queue<pair<ll, int> > pq;
void Dijkstra(int n, int s) {
//vis pq
for(int i = 1; i <= n; i++)
dis[i] = INF;
dis[s] = 0, ans[s] = 1, pq.push({0, s});
while(!pq.empty()) {
int u = pq.top().second;
pq.pop();
if(vis[u])
continue;
vis[u] = 1;
for(auto ei : e[u]) {
int v = ei.v, w = ei.w, k = ei.k;
if(!vis[v] && dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
ans[v] = 1ll * ans[u] * k % MOD;
pq.push({-dis[v], v});
} else if(!vis[v] && dis[v] == dis[u] + w) {
ans[v] = (ans[v] + 1ll * ans[u] * k % MOD) % MOD;
}
}
}
}
int minw[MAXN], minw2[MAXN], dk[MAXN], dk2[MAXN];
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int n, m, q;
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= m; i++) {
int d, v, w;
scanf("%d%d%d", &d, &v, &w);
if(v == 1) {
if(minw[d] == 0 || minw[d] > w) {
minw[d] = w;
dk[d] = 1;
} else if(minw[d] == w)
++dk[d];
} else {
if(minw2[d] == 0 || minw2[d] > w) {
minw2[d] = w;
dk2[d] = 1;
} else if(minw2[d] == w)
++dk2[d];
}
}
for(int d = 1; d <= n; d++) {
if(minw[d])
for(int v = 1; v + d <= n; v += d)
add_edge(v, v + d, minw[d], dk[d]);
if(minw2[d])
for(int v = n; v - d >= 1; v -= d)
add_edge(v - d, v, minw2[d], dk2[d]);
}
Dijkstra(n, 1);
for(int i = 1; i <= q; ++i) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", ans[y]);
}
}