题面:https://www.luogu.org/problem/P4644
和上一篇题解背景基本一样,就是改成了求最小的花费。
本来应该是通过DP和数据结构优化的。
但是最小花费好像可以用最短路。
将每个时间段用自己的价值连边。
再把每个时间向前一个时间连为0的边。
这样可以保证最多可以跑N个时间段的边,且合法。
那么最后假如没有到终点就是失败。
代码如下:
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxm=300005,maxn=100005; int N,M,E; struct node{ int nxt,to; ll dis; #define nxt(x) e[x].nxt #define to(x) e[x].to #define dis(x) e[x].dis }e[maxm]; int head[maxm],tot; inline void add(int u,int v,int w){ to(++tot)=v;dis(tot)=(ll)w; nxt(tot)=head[u];head[u]=tot; } ll dis[maxm]; bool inq[maxm]; inline void spfa(){ memset(dis,0x3f,sizeof(dis)); memset(inq,0,sizeof(inq)); queue<int> q; q.push(M);dis[M]=0;inq[M]=1; while(q.size()){ int now=q.front();q.pop();inq[now]=0; for(int i=head[now];i;i=nxt(i)){ int to=to(i); if(dis[to]>dis[now]+dis(i)){ dis[to]=dis[now]+dis(i); if(!inq[to]){ q.push(to);inq[to]=1; } } } } } int main() { scanf("%d%d%d",&N,&M,&E); for(int i=M;i<E;i++) add(i+1,i,0); for(int i=1;i<=N;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); if(u<M) u=M; if(v>E) v=E; add(u,v+1,w); } spfa(); if(dis[E+1]==0x3f3f3f3f3f3f3f3f) printf("-1\n"); else printf("%lld\n",dis[E+1]); return 0; }
那么DP怎么做
粘了蓝书上的std:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 100006, INF = 0x3f3f3f3f; int n, l, r, f[N]; struct T { int l, r, x; bool operator < (const T w) const { return r < w.r; } } a[N], t[N<<2]; void build(int p, int l, int r) { t[p].l = l; t[p].r = r; if (l == r) { t[p].x = f[l]; return; } int mid = (l + r) >> 1; build(p << 1, l, mid); build(p << 1 | 1, mid + 1, r); t[p].x = min(t[p<<1].x, t[p<<1|1].x); } void change(int p, int x, int y) { if (t[p].l == t[p].r) { t[p].x = y; return; } int mid = (t[p].l + t[p].r) >> 1; if (x <= mid) change(p << 1, x, y); else change(p << 1 | 1, x, y); t[p].x = min(t[p<<1].x, t[p<<1|1].x); } int ask(int p, int l, int r) { if (l <= t[p].l && r >= t[p].r) return t[p].x; int mid = (t[p].l + t[p].r) / 2, ans = INF; if (l <= mid) ans = min(ans, ask(p << 1, l, r)); if (r > mid) ans = min(ans, ask(p << 1 | 1, l, r)); return ans; } int main() { cin >> n >> l >> r; for (int i = 1; i <= n; i++) scanf("%d %d %d", &a[i].l, &a[i].r, &a[i].x); sort(a + 1, a + n + 1); memset(f, 0x3f, sizeof(f)); f[l] = 0; build(1, l, r); for (int i = 1; i <= n; i++) { f[a[i].r] = min(f[a[i].r], ask(1, a[i].l - 1, a[i].r) + a[i].x); change(1, a[i].r, f[a[i].r]); if (a[i].r >= r) { if (f[a[i].r] == INF) puts("-1"); else cout << f[a[i].r] << endl; return 0; } } return 0; }