最短路
单源最短路的建图方式
边权非负 dijkstra
有负权边 spfa
难度在于问题的转化和抽象(如何转化成最短路问题)
热浪(dijkstra模板)
#include <bits/stdc++.h>
using namespace std;
const int N = 2505;
int n, dis[N], m, s, e, vis[N];
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX;
dis[s] = 0;
q.push((edge){s, 0});
while(!q.empty())
{
edge x = q.top();
q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[y.v] > dis[x.v] + y.w)
{
dis[y.v] = dis[x.v] + y.w;
q.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d %d %d", &n, &m ,&s, &e);
for (int i = 1; i <= m; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[u].push_back((edge){v, w});
g[v].push_back((edge){u, w});
}
dijkstra();
printf("%d", dis[e]);
return 0;
}
信使
#include <bits/stdc++.h>
using namespace std;
const int N = 2505;
int n, dis[N], m, s, e, vis[N];
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX;
dis[s] = 0;
q.push((edge){s, 0});
while(!q.empty())
{
edge x = q.top();
q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[y.v] > dis[x.v] + y.w)
{
dis[y.v] = dis[x.v] + y.w;
q.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d", &n, &m);
s = 1;
for (int i = 1; i <= m; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[u].push_back((edge){v, w});
g[v].push_back((edge){u, w});
}
dijkstra();
int ans = 0;
for (int i = 1; i <= n; ++ i) ans = max(ans, dis[i]);
if(ans == INT_MAX) ans = -1;
printf("%d", ans);
return 0;
}
香甜的黄油
暴力枚举每一个作为原点的答案
#include <bits/stdc++.h>
using namespace std;
const int N = 805;
int n, dis[N], vis[N], p, c, cow[N], ans = INT_MAX;
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int s)
{
for (int i = 1; i <= p; ++ i) dis[i] = INT_MAX, vis[i] = 0;
dis[s] = 0;
q.push((edge){s, 0});
while(!q.empty())
{
edge x = q.top();
q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[y.v] > dis[x.v] + y.w)
{
dis[y.v] = dis[x.v] + y.w;
q.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d %d", &n, &p, &c);
for (int i = 1; i <= n; ++ i)
{
int x; scanf("%d", &x);
cow[x] ++;
}
for (int i = 1; i <= c; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[u].push_back((edge){v, w});
g[v].push_back((edge){u, w});
}
for (int i = 1; i <= p; ++ i)
{
dijkstra(i);
int sum = 0;
for (int j = 1; j <= p; ++ j) sum = sum + cow[j] * dis[j];
ans = min(ans, sum);
}
printf("%d", ans);
return 0;
}
最小花费
加法变成了乘法,但是本质没有什么区别
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int s, e, n, m;
typedef long double db;
db dis[N];
bool vis[N];
struct edge
{
int v;
db w;
bool operator < (const edge &a) const {return w < a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int s)
{
dis[s] = 1.0;
q.push((edge){s, 1.0});
while(!q.empty())
{
edge x = q.top();
q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[y.v] < dis[x.v] * y.w)
{
dis[y.v] = dis[x.v] * y.w;
q.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++ i)
{
int u, v;
db w;
scanf("%d %d %Lf", &u, &v, &w);
g[u].push_back((edge){v, 1.0 - w / 100.0});
g[v].push_back((edge){u, 1.0 - w / 100.0});
}
scanf("%d %d", &s, &e);
dijkstra(s);
printf("%.8Lf", 100.0 / dis[e]);
return 0;
}
最优乘车
#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int a[N], n, m, dis[N], vis[N];
vector<int> g[N];
string s;
void bfs()
{
queue<int> q;
dis[1] = 0;
q.push(1);
while(!q.empty())
{
int x = q.front();
q.pop();
if(vis[x]) continue;
vis[x] = 1;
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
if(dis[y] > dis[x] + 1)
{
dis[y] = dis[x] + 1;
q.push(y);
}
}
}
return ;
}
int main()
{
scanf("%d %d", &m, &n);
getchar();
for (int i = 1; i <= m; ++ i)
{
getline(std::cin, s);
int x = 0, cnt = 0;
for (int j = 0; j < s.length(); ++ j)
{
if(s[j] >= '0' && s[j] <= '9') x = x * 10 + s[j] - '0';
else a[++ cnt] = x, x = 0;
}
a[++ cnt] = x;
for (x = 1; x <= cnt; ++ x)
{
for (int y = x + 1; y <= cnt; ++ y) g[a[x]].push_back(a[y]);
}
}
for (int i = 1; i <= n; ++ i) dis[i] = 0x3f3f3f3f;
bfs();
if(dis[n] == 0x3f3f3f3f) printf("NO");
else printf("%d", dis[n] - 1);
return 0;
}
昂贵的聘礼
一个需要分段跑的最短路
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int d, n, dis[N], L[N];
bool vis[N];
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int l, int r)
{
for (int i = 0; i <= n; ++ i) dis[i] = INT_MAX, vis[i] = 0;
dis[0] = 0; q.push((edge){0, 0});
while(!q.empty())
{
edge x = q.top(); q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(l <= L[y.v] && L[y.v] <= r && dis[y.v] > dis[x.v] + y.w)
{
dis[y.v] = dis[x.v] + y.w;
q.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d", &d, &n);
for (int i = 1; i <= n; ++ i)
{
int c, l, x;
scanf("%d %d %d", &c, &L[i], &x);
g[0].push_back((edge){i, c});
for (int j = 1; j <= x; ++ j)
{
scanf("%d %d", &l, &c);
g[l].push_back((edge){i, c});
}
}
int ans = INT_MAX;
for (int i = L[1] - d; i <= L[1]; ++ i)
{
dijkstra(i, i + d);
ans = min(ans, dis[1]);
}
printf("%d", ans);
}
单源最短路的综合应用
新年好
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dis[6][N], m;
bool vis[N];
pair<int, int> a[6];
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra(int z, int s)
{
for (int i = 0; i <= n; ++ i) vis[i] = 0, dis[z][i] = INT_MAX;
dis[z][s] = 0; q.push((edge){s, 0});
while(!q.empty())
{
edge x = q.top(); q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[z][y.v] > dis[z][x.v] + y.w)
{
dis[z][y.v] = dis[z][x.v] + y.w;
q.push((edge){y.v, dis[z][y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= 5; ++ i) scanf("%d", &a[i].first), a[i].second = i;
for (int i = 1; i <= m; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[u].push_back((edge){v, w});
g[v].push_back((edge){u, w});
}
dijkstra(0, 1);
for (int i = 1; i <= 5; ++ i) dijkstra(a[i].second, a[i].first);
sort(a + 1, a + 5 + 1);
int ans = INT_MAX;
do
{
int sum = dis[0][a[1].first];
for (int i = 2; i <= 5; ++ i) sum += dis[a[i - 1].second][a[i].first];
ans = min(ans, sum);
}while(next_permutation(a + 1, a + 5 + 1));
printf("%d", ans);
return 0;
}
通信线路
二分判断就可以了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 10005;
int n, m, k;
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
int eu[M], ev[M], ew[M], dis[N];
bool vis[N];
priority_queue<edge> q;
void dijkstra()
{
for (int i = 0; i <= n; ++ i) vis[i] = 0, dis[i] = INT_MAX;
dis[1] = 0; q.push((edge){1, 0});
while(!q.empty())
{
edge x = q.top(); q.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[y.v] > dis[x.v] + y.w)
{
dis[y.v] = dis[x.v] + y.w;
q.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
bool check(int x)
{
for (int i = 1; i <= n; ++ i) g[i].clear();
for (int i = 1; i <= m; ++ i)
{
int w = 1;
if(ew[i] <= x) w = 0;
g[eu[i]].push_back((edge){ev[i], w});
g[ev[i]].push_back((edge){eu[i], w});
}
dijkstra();
if(dis[n] <= k) return true;
return false;
}
int main()
{
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= m; ++ i)
{
scanf("%d%d%d", &eu[i], &ev[i], &ew[i]);
}
int l = 0, r = 1000000, mid, ans = INT_MAX;
while(l <= r)
{
mid = l + r >> 1;
if(check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
if(ans == INT_MAX) printf("-1");
else printf("%d", ans);
return 0;
}
道路与航线
1.如果所有边权非负,可以用Dijkstra,时间\(O(mlog_{n})\)
2.如果是拓扑图,不管边权为正为负,均可按拓扑序扫描,时间\(O(n)\)
因为题目中存在A -> B的航线就不存在B -> A的航线和道路,所以所有的道路可以变成一个团,并且团的内部一定没有航线。团与团之间一定存在拓扑序。
所以在每一个团内部用dijkstra,团与团之间用拓扑序来处理就可以了。
#include <bits/stdc++.h>
using namespace std;
const int N = 25005;
int n, dis[N], cnt = 0, R, P, S, fa[N], in[N];
bool vis[N], pd[N];
struct edge
{
int v, w, u;
bool operator < (const edge &a) const {return w > a.w;}
};
vector<edge> g[N], p[N];
vector<int> z[N];
queue<int> q;
priority_queue<edge> h;
int findset(int x)
{
if(fa[x] == x) return x;
else return fa[x] = findset(fa[x]);
}
void dijkstra(int s)
{
for (int i = 0; i < z[s].size(); ++ i) h.push((edge){z[s][i], dis[z[s][i]]});
while(!h.empty())
{
edge x = h.top();
h.pop();
if(vis[x.v]) continue;
vis[x.v] = 1;
for (int i = 0; i < g[x.v].size(); ++ i)
{
edge y = g[x.v][i];
if(dis[y.v] > dis[x.v] + y.w)
{
dis[y.v] = dis[x.v] + y.w;
h.push((edge){y.v, dis[y.v]});
}
}
}
return ;
}
int main()
{
scanf("%d %d %d %d", &n, &R, &P, &S);
for (int i = 1; i <= n; ++ i) fa[i] = i;
for (int i = 1; i <= R; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[u].push_back((edge){v, w});
g[v].push_back((edge){u, w});
u = findset(u), v = findset(v);
if(u == v) continue;
fa[u] = v;
}
for (int i = 1; i <= P; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
p[findset(u)].push_back((edge){v, w, u});
in[findset(v)] ++;
}
for (int i = 1 ; i <= n; ++ i) dis[i] = INT_MAX;
int s = findset(S);
dis[S] = 0, pd[s] = true;
z[s].push_back(S);
for (int i = 1; i <= n; ++ i)
{
if(i == findset(i) && !in[i]) q.push(i);
}
while(!q.empty())
{
int x = q.front(); q.pop();
if(pd[x]) dijkstra(x);
for (int i = 0; i < p[x].size(); ++ i)
{
int y = p[x][i].v;
int fy = findset(y);
if(dis[p[x][i].u] != INT_MAX && dis[y] > dis[p[x][i].u] + p[x][i].w)
{
dis[y] = dis[p[x][i].u] + p[x][i].w;
z[fy].push_back(y), pd[fy] = true;
}
in[fy] --;
if(!in[fy]) q.push(fy);
}
}
for (int i = 1; i <= n; ++ i)
{
if(dis[i] == INT_MAX) printf("NO PATH\n");
else printf("%d\n", dis[i]);
}
return 0;
}
最优贸易
求出所有从1到i经过城市的买入的最小值\(dmin[i]\)
和所有从i走到n经过的城市中卖出的最大值\(dmax[i]\)
那么就能算出以i为分界的(包括i)赚取的最大价值为\(dmax[i] - dmin[i]\)
因为图中是有环形的,所以不能使用dp,可以转化成最短路问题。
能用dijkstra的核心就是将这个点从堆取出来的时候,这个点的最小值一定不会再被其它的节点更新了。(但是因为这个题目中有环,所以这个点取出来后可能被其它节点更新)
spfa算法的适用范围更加广泛。spfa算法和bellman_ford算法是等价的。其步骤是迭代n - 1(路径长度最多是n - 1)次,循环所有边,用三角不等式更新。只要路径的边数是小于等于n - 1的,bellman_ford算法就是正确的
代码一遍过!
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, a[N], m, ans = 0, dmin[N], dmax[N];
queue<int> q;
vector<int> g[N], f[N];
bool vis[N];
void spfamin()
{
for (int i = 1; i <= n; ++ i) vis[i] = 0, dmin[i] = INT_MAX;
dmin[1] = a[1]; q.push(1), vis[1] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
vis[x] = 0;
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
if(dmin[y] > min(dmin[x], a[y]))
{
dmin[y] = min(dmin[x], a[y]);
if(!vis[y]) q.push(y), vis[y] = 1;
}
}
}
return ;
}
void spfamax()
{
for (int i = 1; i <= n; ++ i) vis[i] = 0, dmax[i] = 0;
dmax[n] = a[n], q.push(n), vis[n] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
vis[x] = 0;
for (int i = 0; i < f[x].size(); ++ i)
{
int y = f[x][i];
if(dmax[y] < max(dmax[x], a[y]))
{
dmax[y] = max(dmax[x], a[y]);
if(!vis[y]) q.push(y), vis[y] = 1;
}
}
}
return ;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
for (int i = 1; i <= m; ++ i)
{
int u, v, c;
scanf("%d %d %d", &u, &v, &c);
g[u].push_back(v);
f[v].push_back(u);
if(c == 2) g[v].push_back(u), f[u].push_back(v);
}
spfamin();
spfamax();
for (int i = 1; i <= n; ++ i) ans = max(ans, dmax[i] - dmin[i]);
printf("%d", ans);
return 0;
}
单源最短路的扩展应用
选择最佳线路
看数据范围其实可以暴力跑最短路,但是有一个特点就是终点都是一样的。
可以跑反图,或者直接建立一个虚点。
我发现题目里要到的点字母是s,这是暗示吗
一遍过。
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int w, n, m, s, dis[N], ans;
bool vis[N];
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX, vis[i] = 0;
dis[s] = 0; q.push((edge){s, 0});
while(!q.empty())
{
int x = q.top().v; q.pop();
if(vis[x]) continue;
vis[x] = 1;
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i].v;
if(dis[y] > dis[x] + g[x][i].w)
{
dis[y] = dis[x] + g[x][i].w;
q.push((edge){y, dis[y]});
}
}
}
return ;
}
int main()
{
while(scanf("%d %d %d", &n, &m, &s) != EOF)
{
for (int i = 1; i <= n; ++ i) g[i].clear();
for (int i = 1; i <= m; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[v].push_back((edge){u, w});
}
dijkstra();
scanf("%d", &w);
ans = INT_MAX;
for (int i = 1; i <= w; ++ i)
{
int x;
scanf("%d", &x);
ans = min(ans, dis[x]);
}
if(ans == INT_MAX) ans = -1;
printf("%d\n", ans);
}
return 0;
}
拯救大兵瑞恩
能用dp转移的状态直接连边。之间的代价就是边权。
#include <bits/stdc++.h>
using namespace std;
const int N = 12;
int n, m, p, s, k;
int rx[5] = {-1, 1, 0, 0};
int ry[5] = {0, 0, -1, 1};
struct edge
{
int x, y, st, w;
bool operator < (const edge &a) const {return w > a.w; }
};
priority_queue<edge> q;
vector<edge> g[N][N][1025];
int dis[N][N][1025], mp[N][N][N][N], ky[N][N];
bool vis[N][N][1025];
void dijkstra()
{
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= m; ++ j)
{
for (int st = 0; st < (1 << p); ++ st) dis[i][j][st] = INT_MAX, vis[i][j][st] = 0;
}
}
dis[1][1][0] = 0;
q.push((edge){1, 1, 0, 0});
while(!q.empty())
{
edge a = q.top(); q.pop();
if(vis[a.x][a.y][a.st]) continue;
vis[a.x][a.y][a.st] = 1;
for (int i = 0; i < g[a.x][a.y][a.st].size(); ++ i)
{
edge b = g[a.x][a.y][a.st][i];
if(dis[b.x][b.y][b.st] > dis[a.x][a.y][a.st] + b.w)
{
dis[b.x][b.y][b.st] = dis[a.x][a.y][a.st] + b.w;
q.push((edge){b.x, b.y, b.st, dis[b.x][b.y][b.st]});
}
}
}
return ;
}
int main()
{
scanf("%d %d %d", &n, &m, &p);
scanf("%d", &k);
for (int i = 1; i <= k; ++ i)
{
int x, y, a, b, c;
scanf("%d %d %d %d %d", &x, &y, &a, &b, &c);
if(c == 0) mp[x][y][a][b] = -1, mp[a][b][x][y] = -1;
else mp[x][y][a][b] = c, mp[a][b][x][y] = c;
}
scanf("%d", &s);
for (int i = 1; i<= s; ++ i)
{
int x, y, c;
scanf("%d %d %d", &x, &y, &c);
ky[x][y] = ky[x][y] | (1 << (c - 1));
}
for (int x = 1; x <= n; ++ x)
{
for (int y = 1; y <= m; ++ y)
{
for (int st = 0; st < (1 << p); ++ st)
{
if((st | ky[x][y]) != st) g[x][y][st].push_back((edge){x, y, st | ky[x][y], 0});
int sst = (st | ky[x][y]);
for (int i = 0; i < 4; ++ i)
{
int nx = x + rx[i], ny = y + ry[i], nst = (sst | ky[nx][ny]);
if(nx <= 0 || ny <= 0 || nx > n || ny > m) continue;
if(mp[x][y][nx][ny] == 0)
{
g[x][y][sst].push_back((edge){nx, ny, nst, 1});
}
else if(mp[x][y][nx][ny] != -1)
{
if((sst >> (mp[x][y][nx][ny] - 1)) & 1)
{
g[x][y][sst].push_back((edge){nx, ny, nst, 1});
}
}
}
}
}
}
dijkstra();
int ans = INT_MAX;
for (int st = 0; st < (1 << p); ++ st) ans = min(ans, dis[n][m][st]);
if(ans == INT_MAX) ans = -1;
printf("%d", ans);
return 0;
}
最短路计数
#include <bits/stdc++.h>
using namespace std;
const int N = 100005, mod = 100003;
int n, dis[N], cnt[N], m;
bool vis[N];
struct edge
{
int v, w;
bool operator < (const edge &a) const {return w > a.w; }
};
vector<int> g[N];
priority_queue<edge> q;
void dijkstra()
{
for (int i = 1; i <= n; ++ i) dis[i] = INT_MAX, vis[i] = 0;
q.push((edge){1, 0});
dis[1] = 0, cnt[1] = 1;
while(!q.empty())
{
int x = q.top().v;
q.pop();
if(vis[x]) continue;
vis[x] = 1;
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
if(dis[y] == dis[x] + 1) cnt[y] = (cnt[y] + cnt[x]) % mod;
else if(dis[y] > dis[x] + 1)
{
dis[y] = dis[x] + 1;
cnt[y] = cnt[x];
q.push((edge){y, dis[y]});
}
}
}
return ;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++ i)
{
int x, y;
scanf("%d %d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
dijkstra();
for (int i = 1; i <= n; ++ i) printf("%d\n", cnt[i]);
return 0;
}
观光
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, inf = 1000000000;
int n, dis[N][2], cnt[N][2], m, s, e;
bool vis[N][2];
struct edge
{
int v, t, w;
bool operator < (const edge &a) const {return w > a.w; }
};
vector<edge> g[N];
priority_queue<edge> q;
void dijkstra()
{
for (int i = 1; i <= n; ++ i) dis[i][0] = dis[i][1] = inf, cnt[i][0] = cnt[i][1] = 0, vis[i][1] = vis[i][0] = 0;
q.push((edge){s, 0, 0});
dis[s][0] = 0, cnt[s][0] = 1;
while(!q.empty())
{
int x = q.top().v, t = q.top().t; q.pop();
if(vis[x][t]) continue;
vis[x][t] = 1;
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i].v, w = g[x][i].w;
if(dis[y][0] == dis[x][t] + w) cnt[y][0] += cnt[x][t];
else if(dis[y][0] > dis[x][t] + w)
{
dis[y][1] = dis[y][0], cnt[y][1] = cnt[y][0];
q.push((edge){y, 1, dis[y][1]});
dis[y][0] = dis[x][t] + w, cnt[y][0] = cnt[x][t];
q.push((edge){y, 0, dis[y][0]});
}
else if(dis[y][1] == dis[x][t] + w) cnt[y][1] += cnt[x][t];
else if(dis[y][1] > dis[x][t] + w)
{
dis[y][1] = dis[x][t] + w, cnt[y][1] = cnt[x][t];
q.push((edge){y, 1, dis[y][1]});
}
}
}
return ;
}
int main()
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i) g[i].clear();
for (int i = 1; i <= m; ++ i)
{
int x, y, w;
scanf("%d %d %d", &x, &y, &w);
g[x].push_back((edge){y, 0, w});
}
scanf("%d %d", &s, &e);
dijkstra();
if(dis[e][1] == dis[e][0] + 1) printf("%d\n", cnt[e][0] + cnt[e][1]);
else printf("%d\n", cnt[e][0]);
}
return 0;
}
2024.10.10
Piggy Back
#include <bits/stdc++.h>
using namespace std;
const int N = 40005, inf = 0x3f3f3f3f;
int B, E, P, n, m, ans = inf;
vector<int> g[N];
int dis[3][N];
void dijkstra(int s, int id)
{
queue<int> q;
q.push(s);
dis[id][s] = 0;
while(!q.empty())
{
int x = q.front();
q.pop();
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
if(dis[id][y] != inf) continue;
dis[id][y] = dis[id][x] + 1;
q.push(y);
}
}
return ;
}
int main()
{
scanf("%d %d %d %d %d", &B, &E, &P, &n, &m);
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= m; ++ i)
{
int x, y;
scanf("%d %d", &x, &y);
g[x].push_back(y), g[y].push_back(x);
}
dijkstra(1, 1);
dijkstra(2, 2);
dijkstra(n, 0);
for (int i = 1; i <= n; ++ i )
{
ans = min(ans, dis[1][i] * B + dis[2][i] * E + dis[0][i] * P);
}
printf("%d", ans);
return 0;
}
[AGC039B] Graph Partition
#include <bits/stdc++.h>
using namespace std;
const int N = 205, inf = 0x3f3f3f3f;
int n, ans = -1, dis[N];
char mp[N];
vector<int> g[N];
void bfs(int s)
{
for (int i = 1; i <= n; ++ i) dis[i] = -1;
dis[s] = 1;
bool pd = true; int mx = 0;
queue<int> q;
q.push(s);
while(!q.empty())
{
int x = q.front();
mx = max(mx, dis[x]);
q.pop();
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
if(dis[y] == -1)
{
dis[y] = dis[x] + 1;
q.push(y);
}
else
{
if(abs(dis[y] - dis[x]) != 1) pd = false;
}
if(!pd) break;
}
if(!pd) break;
}
if(pd) ans = max(ans, mx);
return ;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i)
{
scanf("%s", mp + 1);
for (int j = 1; j <= n; ++ j)
{
if(mp[j] == '1') g[i].push_back(j);
}
}
for (int i = 1; i <= n; ++ i) bfs(i);
printf("%d", ans);
return 0;
}
Sums(同余最短路)
#include <bits/stdc++.h>
using namespace std;
const int N = 500005, inf = 1000000001;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
int n, dis[N], mx = inf, a[N];
bool vis[N];
int read()
{
int x = 0;char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
void dijkstra()
{
for (int i = 0; i <= mx - 1; ++ i) dis[i] = inf;
q.push(make_pair(0, 0));
dis[0] = 0;
while(!q.empty())
{
int x = q.top().second;
q.pop();
if(vis[x]) continue;
vis[x] = 1;
for (int i = 1; i <= n; ++ i)
{
if(a[i] == mx) continue;
int y = (x + a[i]) % mx;
if(dis[y] > (long long)dis[x] + a[i])
{
dis[y] = dis[x] + a[i];
q.push(make_pair(dis[y], y));
}
}
}
return ;
}
int main()
{
n = read();
for (int i = 1; i <= n; ++ i)
{
a[i] = read();
mx = min(mx, a[i]);
}
dijkstra();
int k;
k = read();
while(k --)
{
int x;
x = read();
if(x >= dis[x % mx]) printf("TAK\n");
else printf("NIE\n");
}
return 0;
}

浙公网安备 33010602011771号