【集训】最短路!

news/2025/2/8 19:38:42/文章来源:https://www.cnblogs.com/fanrunze/p/18705261

最短路

P4779 【模板】单源最短路径(标准版)

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int N = 200005;int n, m, s;int h[N], e[N << 1], ne[N << 1], w[N << 1], idx;vector<PII> v[N];int dis[N];struct node{int d, id;bool friend operator<(node a,node b){return a.d > b.d;}};void add(int u,int v,int W){e[++idx] = v, ne[idx] = h[u], w[idx] = W, h[u] = idx;}priority_queue<node> q;void dij(){memset(dis, 0x3f, sizeof(dis));dis[s] = 0;q.push({0, s});while(!q.empty()){int d = q.top().d, u = q.top().id;q.pop();if(d>dis[u])continue;for (int i = h[u]; i;i=ne[i]){int v = e[i];if(dis[v]>dis[u]+w[i]){dis[v] = dis[u] + w[i];q.push({dis[v], v});}}}}void Main(){cin >> n >> m >> s;for (int i = 1; i <= m;i++){int u, v, w;cin >> u >> v >> w;add(u, v, w);}dij();for (int i = 1; i <= n;i++)cout << dis[i] << " ";}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;// T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

P5905 【模板】全源最短路(Johnson)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << '=' << x << endlinline int rd() {int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9') {if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}void print(ll x) {if (x < 0)putchar('-'), x = -x;if (x > 9)print(x / 10);putchar(x % 10 + '0');return;
}namespace Star_F {struct edge {int v, w, next;
} e[10005];struct node {int dis, id;bool operator<(const node& a) const { return dis > a.dis; }node(int d, int x) { dis = d, id = x; }
};const int INF = 1e9;
int head[5005], vis[5005], t[5005];
int cnt, n, m;
long long h[5005], dis[5005];void addedge(int u, int v, int w) {e[++cnt].v = v;e[cnt].w = w;e[cnt].next = head[u];head[u] = cnt;
}bool spfa(int s) {queue<int> q;memset(h, 63, sizeof(h));h[s] = 0, vis[s] = 1;q.push(s);while (!q.empty()) {int u = q.front();q.pop();vis[u] = 0;for (int i = head[u]; i; i = e[i].next) {int v = e[i].v;if (h[v] > h[u] + e[i].w) {h[v] = h[u] + e[i].w;if (!vis[v]) {vis[v] = 1;q.push(v);t[v]++;if (t[v] == n + 1) return false;}}}}return true;
}void dijkstra(int s) {priority_queue<node> q;for (int i = 1; i <= n; i++) dis[i] = INF;memset(vis, 0, sizeof(vis));dis[s] = 0;q.push(node(0, s));while (!q.empty()) {int u = q.top().id;q.pop();if (vis[u]) continue;vis[u] = 1;for (int i = head[u]; i; i = e[i].next) {int v = e[i].v;if (dis[v] > dis[u] + e[i].w) {dis[v] = dis[u] + e[i].w;if (!vis[v]) q.push(node(dis[v], v));}}}return;
}void Main() {n = rd(); m = rd();for (int i = 1; i <= m; i++) {int u = rd(), v = rd(), w = rd();addedge(u, v, w);}for (int i = 1; i <= n; i++) addedge(0, i, 0);if (!spfa(0)) {cout << -1 << endl;return;}for (int u = 1; u <= n; u++)for (int i = head[u]; i; i = e[i].next) e[i].w += h[u] - h[e[i].v];for (int i = 1; i <= n; i++) {dijkstra(i);long long ans = 0;for (int j = 1; j <= n; j++) {if (dis[j] == INF)ans += j * INF;elseans += j * (dis[j] + h[j] - h[i]);}cout << ans << endl;}
}}signed main() {// freopen(".in", "r", stdin);// freopen(".out", "w", stdout);return Star_F::Main(), 0;
}

P3385 【模板】负环

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int N = 2005;int dis[N], cnt[N];vector<PII> G[N];bool vis[N];int n, m;bool spfa(){queue<int> q;vis[1] = 1, dis[1] = 0, cnt[1] = 1;q.push(1);while(!q.empty()){int u = q.front();q.pop();vis[u] = 0;for (int i = 0; i < G[u].size();i++){int v = G[u][i].fi, w = G[u][i].se;if(dis[v]>dis[u]+w){dis[v] = dis[u] + w;if(!vis[v]){cnt[v]++;q.push(v);if(cnt[v]>=n)return true;}}}}return false;}void Main(){memset(dis, 0x3f, sizeof(dis));memset(vis, 0, sizeof(vis));memset(cnt, 0, sizeof(cnt));cin >> n >> m;for (int i = 1; i <= n;i++)G[i].clear();for (int i = 1; i <= m;i++){int u, v, w;cin >> u >> v >> w;G[u].push_back({v, w});if(w>=0)G[v].push_back({u, w});}cout << (spfa() ? "YES" : "NO") << endl;}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

P1119 灾后重建

动态加边,动态求全源最短路。

由于输入的时间 \(t\) 按升序排序,不用再排序。直接暴力加边,用 \(\text{Floyd}\) 维护全源最短路即可。

注意编号是 \(0 \sim N-1\) ,所以数组从 \(0\) 开始。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int N = 205;int T, n, m, a[N], f[N][N];void update(int k){for (int i = 0; i < n;i++){for (int j = 0; j < n;j++)f[i][j] = f[j][i] = min(f[i][j], f[i][k] + f[k][j]);}}void Main(){cin >> n >> m;for (int i = 0; i < n;i++)cin >> a[i];memset(f, 0x3f, sizeof(f));for (int i = 0; i <= n;i++)f[i][i] = 0;for (int i = 1; i <= m;i++){int u, v, w;cin >> u >> v >> w;f[u][v] = f[v][u] = w;}cin >> T;int x = 0;while(T--){int u, v, t;cin >> u >> v >> t;while(a[x]<=t&&x<n)update(x++);if(a[u]>t||a[v]>t)cout << -1 << endl;else{if(f[u][v]==0x3f3f3f3f)cout << -1 << endl;elsecout << f[u][v] << endl;}}}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;// T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

P1462 通往奥格瑞玛的道路

看到最大值最小,果断考虑二分。

我们二分一个 \(mid\),每次只经过边权小于 \(mid\) 的边,判断是否能到达终点。

如何判断?和最短路类似,我们用 dis[v]=dis[u]-w[i] 更新 dis 数组即可,所以用大根堆维护。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int N = 10005, M = 100005, INF = 0x3f3f3f3f;int h[N], ne[M], e[M], w[M], idx;int n, m, k;int a[N], l = INF, r, flag;void add(int u,int v,int W){e[++idx] = v, ne[idx] = h[u], w[idx] = W, h[u] = idx;}int dis[N];priority_queue<PII> q;bool check(int mid){memset(dis, -1, sizeof(dis));dis[1] = k;q.push({dis[1], 1});while(!q.empty()){int u = q.top().se, d = q.top().fi;q.pop();if(dis[u]!=d)continue;for (int i = h[u]; i;i=ne[i]){int v = e[i];if(a[v]>mid)continue;if(dis[v]<dis[u]-w[i]&&dis[u]-w[i]>=0){dis[v] = dis[u] - w[i];q.push({dis[v], v});}}}return dis[n] != -1;}void Main(){cin >> n >> m >> k;for (int i = 1; i <= n;i++){cin >> a[i];l = min(l, a[i]), r = max(r, a[i]);}flag = r;for (int i = 1; i <= m;i++){int u, v, w;cin >> u >> v >> w;add(u, v, w), add(v, u, w);}l = a[1];while(l<=r){int mid = l + r >> 1;if(check(mid))r = mid - 1;elsel = mid + 1;}if(l==flag+1)cout << "AFK" << endl;elsecout << l << endl;}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;// T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

UVA11090 Going in Cycle!!

经典套路二分题

二分答案 \(w\),原式 \(\sum c_i\ge w \times *cnt\)。化简得 \(\sum^{cnt}(c_i-w)\ge 0\)。转换为找负环。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int INF = 0x3f3f3f3f;const int N = 305, M = 15000;int m, n;int h[N], e[M], ne[M], idx;double w[M];int tmp = 1;void add(int u,int v,double W){e[++idx] = v, ne[idx] = h[u], w[idx] = W, h[u] = idx;}int nm[N], vis[N];double dis[N];bool spfa(double x){queue<int> q;memset(vis, 1, sizeof(vis));for (int i = 1; i <= n;i++)dis[i] = (double)INF;memset(nm, 0, sizeof(nm));for (int i = 1; i <= m;i++)w[i] -= x;for (int i = 1; i <= n;i++)q.push(i);while(!q.empty()){int now = q.front();q.pop();vis[now] = 0;for (int i = h[now]; i;i=ne[i]){int v=e[i];if(dis[v]>=dis[now]+w[i]){dis[v] = dis[now] + w[i];nm[v] = nm[now] + 1;if(vis[v]==0){q.push(v);}if(nm[v]>=n+1){for (int i = 1; i <= m;i++)w[i] += x;return 1;}}}}for (int i = 1; i <= n;i++) w[i]+=x;return 0;}void Main(){idx = 0;memset(h, 0, sizeof(h));cin >> n >> m;for (int i = 1; i <= m;i++){int u, v, w;cin >> u >> v >> w;add(u, v, (double)w);}double l = 0, r = 100000001;while(r-l>0.0000001){double mid = (l + r) / 2;if(spfa(mid))r = mid;else l = mid;}cout << "Case #" << tmp++ << ": ";if(r==100000001)cout << "No cycle found." << endl;elseprintf("%.2lf\n", l);}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

P2865 [USACO06NOV] Roadblocks G

单源次短路模板题目

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int N=200005;int n, m;int h[N], e[N], ne[N], w[N], idx;int dis[2][N];void add(int u,int v,int W){e[++idx] = v, ne[idx] = h[u], w[idx] = W, h[u] = idx;}struct node{int id, d;bool friend operator<(node a,node b){return a.d > b.d;}};priority_queue<node> q;void dij(){for (int i = 1; i <= n;i++)dis[0][i] = dis[1][i] = 2147483647;dis[0][1] = 0;q.push({1, 0});while(!q.empty()){int u = q.top().id, d = q.top().d;q.pop();if(d>dis[1][u])continue;for (int i = h[u]; i;i=ne[i]){int v = e[i];if(dis[0][v]>d+w[i]){dis[1][v] = dis[0][v];dis[0][v] = d + w[i];q.push({v, dis[0][v]});}if(dis[1][v]>d+w[i]&&dis[0][v]<d+w[i]){dis[1][v] = d + w[i];q.push({v, dis[1][v]});}}}}void Main(){cin >> n >> m;for (int i = 1; i <= m;i++){int u, v, w;cin >> u >> v >> w;add(u, v, w), add(v, u, w);}dij();cout << dis[1][n] << endl;}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;// T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

P1875 佳佳的魔法药水

最短路计数问题。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}
#define rd rd()void wt(int x){if (x < 0)putchar('-'), x = -x;if (x > 9)wt(x / 10);putchar(x % 10 + '0');return;
}
void wt(char x){putchar(x);
}
void wt(int x, char k){wt(x),putchar(k);
}namespace Star_F{const int N = 3005;int c[N], ans[N], t[N][N];bool f[N];void Main(){int n;cin >> n;for (int i = 1; i <= n;i++)cin >> c[i], ans[i] = 1;int u, v, w;while(scanf("%d%d%d",&u,&v,&w)!=EOF)t[u + 1][v + 1] = t[v + 1][u + 1] = w + 1;for (int i = 1; i < n;i++){int maxn = 0x3f3f3f3f;int b;for (int j = 1; j <= n;j++)if(!f[j]&&c[j]<maxn)b = j, maxn = c[j];f[b] = 1;for (int j = 1; j <= n;j++)if(f[j]&&t[b][j]){if(c[b]+c[j]==c[t[b][j]])ans[t[b][j]] += ans[b] * ans[j];if(c[b]+c[j]<c[t[b][j]])c[t[b][j]] = c[b] + c[j], ans[t[b][j]] = ans[b] * ans[j];}}cout << c[1] << " " << ans[1] << endl;}}signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);ClockA;int T=1;// T=rd;while(T--) Star_F::Main();// ClockB;return 0;
}

P1948 [USACO08JAN] Telephone Lines S

最大值最小,还是考虑二分。

二分 \(mid\) ,把大于 \(mid\) 的边看为 \(1\),小于等于 \(mid\) 得便看为 \(0\),跑最短路即可

当然更优秀的做法是 01BFS

#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = 20010;
int n, m, k;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
deque<int> q;
bool st[N];
void add(int a, int b, int c){e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
bool check(int bound){memset(dist, 0x3f, sizeof dist);memset(st, 0, sizeof st);q.push_back(1);dist[1] = 0;while (q.size()){int t = q.front();q.pop_front();if (st[t]) continue;st[t] = true;for (int i = h[t]; ~i; i = ne[i]){int j = e[i], x = w[i] > bound;if (dist[j] > dist[t] + x){dist[j] = dist[t] + x;if (!x) q.push_front(j);else q.push_back(j);}}}return dist[n] <= k;
}
int main(){cin >> n >> m >> k;memset(h, -1, sizeof h);while (m -- ){int a, b, c;cin >> a >> b >> c;add(a, b, c), add(b, a, c);}int l = 0, r = 1e6 + 1;while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid;else l = mid + 1;}if (r == 1e6 + 1) cout << -1 << endl;else cout << r << endl;return 0;
}

P2371 [国家集训队] 墨墨的等式

奇妙好题!!

同余最短路:与差分约束有异曲同工之妙,都将约束条件转化为边,每种状态转化为点。把本来与图论毫不相干的问题抽象到具体的图上,通过拓扑排序,最短路等基础算法获得最小状态,从而解决问题。

在本题中,以 \(0\)\(a_1-1\) 为节点,对于检点 \(v\),遍历数组 \(a\),将 \(v\)\((v+a_j) \bmod a_1\) 连一条权值为 \(a_j\) 的边。把图建完之后,就形成了一个有向图,跑最短路后 \(dis_v\) 的值即为用题目给出的数能获得的最小的,对 \(a_1\) 取模为 \(v\) 的值。

$ \forall v$, \(1\) 到 n 中有 \(\frac{n-d i s_{v}}{a_{1}}+1\) 数是可以用题目给出的数到达,所以答案为 $\sum_{i}^{a_{1}-1} \frac{r-d i s_{v}}{a_{1}}- \frac{l-1-d i s_{v}}{a_{1}} $

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << '=' << x << endlinline int rd()
{int x = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-')f = -1;ch = getchar();}while (ch >= '0' && ch <= '9')x = (x << 3) + (x << 1) + ch - '0', ch = getchar();return x * f;
}void print(int x)
{if (x < 0)putchar('-'), x = -x;if (x > 9)print(x / 10);putchar(x % 10 + '0');return;
}namespace Star_F
{#define int long longconst int maxn = 13, N = 5e5 + 10, M = 11 * 5e5 + 10;int n, l, r;int a[maxn];struct edge{int u, v, w, nxt;} e[M];int tot, head[N];void add(int u, int v, int w) { e[++tot] = {u, v, w, head[u]}, head[u] = tot; }struct node{int u, dis;bool operator<(const node &a) const { return dis > a.dis; }};int vis[N], dis[N];void init() { FOR(i, 1, N - 1)dis[i] = 1e18 + 10,vis[i] = 0; }void dj(int s){init();dis[s] = 0;priority_queue<node> q;q.push({s, dis[s]});while (!q.empty()){int u = q.top().u, k = q.top().dis;q.pop();if (vis[u] && k != dis[u])continue;vis[u] = 1;for (int i = head[u]; i; i = e[i].nxt){int v = e[i].v, w = e[i].w;if (dis[v] > dis[u] + w){dis[v] = dis[u] + w;q.push({v, dis[v]});}}}}int minn = 1e18 + 10, id = 0;int sov(int x){int ans = 0;FOR(i, 0, minn - 1){if (dis[i] <= x){ans += (x - dis[i]) / minn + 1;}}return ans;}void Main(){cin >> n >> l >> r;FOR(i, 1, n){cin >> a[i];if (a[i] == 0){i--;n--;continue;}if (minn > a[i])minn = a[i], id = i;}FOR(i, 0, minn - 1){FOR(j, 1, n){if (a[j] == minn)continue;add(i, (i + a[j]) % minn, a[j]);}}dj(0);int ans = sov(r) - sov(l - 1);cout << ans;}
}
signed main(){//freopen("inq.in","r",stdin);//freopen("inq.out","w",stdout);return Star_F::Main(), 0;return 0;
}

P2446 [SDOI2010] 大陆争霸

题解-bits

P8817 [CSP-S 2022] 假期计划

  • \(u\)\(v\) 之间可达意为 \(u\)\(v\) 之间可以不多于 \(k\) 次转车到达,及 \(u\)\(v\) 的距离不多于 \(k+1\)

  • 一个点 \(u\) 在家附近,意为 \(u\) 和 1 之间可达。

注意,为方便,特殊地,我们认为自己和自己不可达。

观察数据范围,\(n^2\) 可过,已经足够处理出每个点对之间的距离了。因此首先应该采用 BFS,\(n^2\) 计算任意点对之间是否可达。

注意:对于满足边权全为 1 的图,单源最短路可以做到 \(\mathcal{O}(n)\) 的复杂度(采用 BFS);

对于满足边权只有 0,1 两种的图,单源最短路也可以做到 \(\mathcal{O}(n)\) 的复杂度(采用 0-1 BFS)。

我们考虑一条 \(1 - a - b - c - d - 1\) 的路径,\(n^4\) 的枚举是不可行的。

很直接的想法是,依次考虑 \(a\)\(b\)\(c\)\(d\),发现贪心是不对的,从 1 选择了更大的权值景点 \(a\),但是可能接下来能到达的 \(b\) 就小的可怜;而选一个权值稍小一点的 \(a\),可能可达的 \(b\) 会很大。

但有一种贪心是对的,那就是确定了 \(a\)\(b\)\(c\),选择 \(d\) 的时候。如果我们确定了 \(c\),那么直接选择 \(c\) 可达的,在家附近的,不为 \(a\) 也不为 \(b\) 的权值最大的景点作为 \(d\) 即可。反正 \(d\) 之后没有景点了,所以可以直接贪心,没有后顾之忧。

由于环的对称性,可以发现确定了 \(b\)\(c\)\(d\) 之后,也可以贪心地选择 \(a\)

有了大体思路。

我们定义 \(f(u)\) 表示 \(u\) 可达,且在家附近的权值最大的景点。

第一步:我们预处理出 \(f(u)\)

第二步:直接 \(n^2\) 枚举,循环确定景点 \(b\)\(c\)\(b \ne c\)),然后记 \(a = f(b)\)\(d = f(c)\),然后试图用 \(w(a) + w(b) + w(c) + w(d)\) 更新答案,其中 \(w(u)\) 表示景点 \(u\) 的权值。

发现重复性的细节是存在问题的,比如:会出现 \(f(b) = c\) 的情况,此时让 \(a = f(b)\) 会导致 \(a = c\),这是不允许的。

不过,贪心思想还是不变的:\(a\) 应该尝试更换为 \(u\) 可达,且在家附近的权值第二大的景点。

更换定义,\(f(u, k)\) 表示 \(u\) 可达,且在家附近的权值第 \(k\) 大的景点。

当发现 \(f(b, 1) = c\) 时,将 \(a\) 设置为 \(f(b, 2)\) 即可。

当发现 \(f(c, 1) = b\) 时,将 \(d\) 设置为 \(f(c, 2)\) 即可。

发现并没有完全解决:如果这样处理后的 \(a\)\(d\) 仍然重复怎么办?

还是贪心思想,考虑把 \(a\) 或者 \(d\) 换成更小的那个比较一下就行,具体来说,比如原先 \(a = f(b, 2)\),就把 \(a\) 下调为 \(f(b, 3)\);或者原先 \(d = f(c, 2)\),就把 \(d\) 下调为 \(f(c, 3)\),然后比较两种方案哪种更好就行了。

重复性解决了,但是还有个细节:如果原先 \(a = f(b, 1)\),发现 \(a = d\),我们想下调 \(a\)。是直接把 \(a\) 设置成 \(f(b, 2)\) 吗?错误,我们还需要检查一下 \(f(b, 2)\) 是否等于 \(c\),如果等于 \(c\) 还需要继续下调到 \(f(b, 3)\)。下调 \(d\) 同理。

至于原先 \(a = f(b, 2)\) 为啥下调 \(a\) 不需检查?因为如果原先 \(a = f(b, 2)\) 了说明 \(f(b, 1)\) 已经等于 \(c\) 了。所以 \(f(b, 3)\) 肯定什么问题都没有。

如果直接这么写是没有问题的,但是麻烦了。下面是一种更好写的处理方法:

直接分别枚举 \(a\) 分别作为 \(f(b, 1)\)\(f(b, 2)\)\(f(b, 3)\)\(d\) 分别作为 \(f(c, 1)\)\(f(c, 2)\)\(f(c, 3)\) 组成的共九种情况,检查互异性然后更新答案即可。

需要提前预处理出 \(f(u, k \le 3)\),其实只要在最开始 BFS 预处理的同时维护一下就行了。

注意某些点可达,还在家附近的点数可能没有 3 个,因此注意类似访问 \(f(b, 3)\) 时产生的越界问题。

如果枚举到某个 \(b\)\(c\),发现 \(b\) 或者 \(c\) 有对应点数不超过 3 的情况时,这组 \(b\)\(c\) 不一定可以生成一组合法的解,属于正常现象。

题目保证全局上是有解的。

#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;const int N = 2510, M = 20010;int n, m, k;
LL w[N];
int h[N], e[M], ne[M], idx;
int dist[N], f[N][4], q[N];
bool st[N][N];void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}void bfs(int start, int f[])
{int hh = 0, tt = 0;memset(dist, 0x3f, sizeof dist);dist[start] = 0;q[0] = start;while (hh <= tt){int t = q[hh ++ ];if (dist[t] == k + 1) continue;for (int i = h[t]; ~i; i = ne[i]){int j = e[i];if (dist[j] > dist[t] + 1){dist[j] = dist[t] + 1;st[start][j] = true;q[ ++ tt] = j;if (st[1][j]){f[3] = j;for (int u = 3; u; u -- )  if (w[f[u]] > w[f[u - 1]])swap(f[u], f[u - 1]);else break;}}}}
}int main()
{scanf("%d%d%d", &n, &m, &k);for (int i = 2; i <= n; i ++ ) scanf("%lld", &w[i]);memset(h, -1, sizeof h);while (m -- ){int a, b;scanf("%d%d", &a, &b);add(a, b), add(b, a);}for (int i = 1; i <= n; i ++ )bfs(i, f[i]);LL res = 0;for (int b = 2; b <= n; b ++ )for (int c = 2; c <= n; c ++ )if (st[b][c])for (int x = 0; x < 3; x ++ )for (int y = 0; y < 3; y ++ ){int a = f[b][x], d = f[c][y];if (a && d && a != d && a != c && b != d)res = max(res, w[a] + w[b] + w[c] + w[d]);}printf("%lld\n", res);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/880940.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

内存占用与监控方式介绍

1.内存占用 神经网络模型常见的内存占用可以分为以下几个部分: 1.1 模型参数内存定义:神经网络的权重和偏置等参数会占用内存。 计算方法:参数总量 = 各层参数数量的总和。 每个参数的大小取决于数据类型(如 float32 为 4 字节,float16 为 2 字节,int8 为 1 字节)。公式…

WebGPU 版 Kokoro:浏览器端零成本使用高质量 TTS;苹果 ELEGNT 台灯机器人:赋予非人形机器人「情感」

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文章 」、「有看点的 会议 」,但内容仅代表编辑…

尝试使用阿里云计算巢部署 DeepSeek-R1

记录一下用阿里云计算巢部署 DeepSeek-R1 的经过。进入阿里云计算巢控制台的服务目录,选择 DeepSeek 社区版,点击「开始部署」,选择最便宜的 ECS 实例 GRID 虚拟化4核30G,费用是 1.748/小时。点击「立即创建」,然后控制台会显示正在部署的状态。部署完成后,控制台会显示公…

未来已来:云手机+AI如何重塑Facebook、Google的智能营销生态

未来已来:云手机+AI如何重塑Facebook、Google的智能营销生态 在数字化浪潮奔涌的当下,科技融合正以令人惊叹的速度重塑各个行业,智能营销领域更是首当其冲。云手机与AI自动化工具的深度融合,为Facebook、Google构建的庞大智能营销生态带来了颠覆性的变革,开拓出全新的发展…

Burp Suite 2024激活汉化

转载自https://blog.csdn.net/m0_52985087/article/details/140299827 前言在项目即将上线阶段,迈入生产环境之际,确保其安全性成为我们不可忽视的首要任务。为筑起一道坚不可摧的安全防线,我们借助业界公认的网络安全利器——Burp Suite,我们将展开一场全面的安全测试,旨…

清华权威出品!104页《DeepSeek从入门到精通》免费领,解锁AI时代的核心竞争力!

引言: 在AI技术席卷全球的今天,如何高效驾驭大模型工具已成为个人与企业脱颖而出的关键。清华大学新闻与传播学院新媒体研究中心元宇宙文化实验室余梦珑博士后团队倾力打造的《DeepSeek从入门到精通》电子书重磅发布!全书104页,从基础操作到高阶技巧,手把手教你玩转国产顶…

win11家庭中文版登录应用提示:“为了对电脑进行保护,已经阻止此应用”

1.家庭中文版组策略里面禁用:以管理员批准模式运行所有管理员 win11打不开组策略,需要复制文本内容到记事本,修改为bat后缀执行 @echo off pushd "%~dp0" dir /b c:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum …

4种比常见的线程池和线程同步买票问题

线程池 所谓的线程池:其实就是线程对象的容器。 可以根据需要,在启动时,创建1个或者多个线程对象。 java中有4种比较常见的线程池。 1.固定数量的线程对象。 2.根据需求动态创建线程:动态创建线程:根据需求来创建线程的个数,会自动给我们分配合适的线程个数来完成任务。 3.…

12. Makefile文件

一、什么是Makefile文件Makefile 文件时一种用于管理和自动化软件编译过程的文本文件。它通常包含了一系列规则,这些规则描述了如何根据源代码文件生成可执行文件或者其它目标文件。Makefile 的核心概念是规则和依赖关系,规则定义了如何生成一个或多个目标文件,而依赖关系则…

busybox 设置登录用户名及密码

1、配置 busybox2、替换新的 /bin/busybox,建立 /bin/login、/sbin/getty 软链接ln -sf /bin/busybox ./bin/login ln -sf /bin/busybox ./sbin/getty3、设置 /etc/inittab 不需要登录:ttyS0::respawn:/bin/ash -l -i需要登录:ttyS0::respawn:/sbin/getty 115200 ttyS04、设…

DoIP 协议详解

转载:车载以太网DoIP 协议,万字长文详解_doip协议-CSDN博客 一、前言 DoIP(Diagnostic Communication over Internet Protocol) 协议是一种用于汽车诊断通信的协议,它允许通过IP网络(如以太网)进行诊断操作。 DoIP协议的设计初衷是为了解决传统基于CAN (Controller Area N…