原题:
在郊区有 N 座通信基站,P 条 双向 电缆,第 i 条电缆连接基站AiAi和BiBi。
特别地,1 号基站是通信公司的总站,N 号基站位于一座农场中。
现在,农场主希望对通信线路进行升级,其中升级第 i 条电缆需要花费LiLi。
电话公司正在举行优惠活动。
农产主可以指定一条从 1 号基站到 N 号基站的路径,并指定路径上不超过 K 条电缆,由电话公司免费提供升级服务。
农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。
求至少用多少钱可以完成升级。
输入格式
第1行:三个整数N,P,K。
第2..P+1行:第 i+1 行包含三个整数Ai,Bi,LiAi,Bi,Li。
输出格式
包含一个整数表示最少花费。
扫描二维码关注公众号,回复:
10766963 查看本文章
若1号基站与N号基站之间不存在路径,则输出”-1”。
数据范围
0≤K<N≤10000≤K<N≤1000,
1≤P≤100001≤P≤10000,
1≤Li≤10000001≤Li≤1000000
输入样例:
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
输出样例:
4
原题地址:https://www.acwing.com/problem/content/342/
两种解法一种是二分+01图跑最短路(最优解),另一种是分层图跑spfa(次解)
二分+01跑最短路check
可以二分答案x,然后check1到n的路径最少走几条大于x的路,如果大于x的路小于等于k就返回true,否则返回false,具体check算法:以x为阈值,大于x的边为1,小于等于x的边为0,然后跑最短路即可
时间复杂度:O(n*mlogm)
AC代码:
#include<iostream> #include<algorithm> #include<cstring> #include<queue> #include<vector> using namespace std; const int Maxn = 1e3 + 10; const int inf = 0x3f3f3f3f; struct Edge{ int v, w; Edge(int v, int w): v(v), w(w) {} }; struct Node{ int v, d; Node(int v, int d) : v(v), d(d) {} bool operator > (const Node& B) const{ return d > B.d; } }; vector<vector<Edge> > G(Maxn); int dist[Maxn]; bool visit[Maxn]; bool check(int n, int k, int x) { priority_queue<Node, vector<Node>, greater<Node> > pq; memset(dist, inf, sizeof(dist)); memset(visit, 0, sizeof(visit)); dist[1] = 0; pq.push(Node(1, 0)); while(!pq.empty()){ Node t = pq.top(); pq.pop(); int u = t.v; if(visit[u]) continue; for(int i=0; i<G[u].size() ;i++){ int v = G[u][i].v; int w = G[u][i].w; if(w > x) w = 1; else w = 0; if(!visit[v] && dist[v] > dist[u] + w){ dist[v] = dist[u] + w; pq.push(Node(v, dist[v])); } } } if(dist[n] <= k) return true; else return false; } int main() { int n, m, p; cin>>n>>m>>p; for(int i=0; i<m ;i++){ int u, v, w; cin>>u>>v>>w; G[u].push_back(Edge(v, w)); G[v].push_back(Edge(u, w)); } int l = 0, r = inf; while(l < r){ int m = l + r >> 1; if(check(n, p, m)) r = m; else l = m + 1; } if(r == inf) cout<<-1; else cout<<r; return 0; }
分层图跑spfa
这个题可以看做是一个K+1层的图,然后把边变成免费操作可以看成是两点间有一条权值为0的边,但是经过这条边的同时会进入下一层图,因为最多只有K+1层图,所以最多只能通过K次0权边。因此在这种分层图里跑最短路,然后每一层到n结点的路径的最小值就是答案。最坏情况下的时间复杂度应该是O(n*k*m),本该超时的,但是这个题居然能过,说明是数据水了,所以这个只能是次优解
#include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<queue> using namespace std; struct Edge{ int v, w; Edge(int v, int w): v(v), w(w) {} }; struct Node{ int v, d, p; Node(int v, int d, int p) : v(v), d(d), p(p) {} }; const int Maxn = 1e3 + 10; const int inf = 0x3f3f3f3f; vector<vector<Edge> > G(Maxn); int dist[Maxn][Maxn]; void spfa(int n, int k) { memset(dist, inf, sizeof(dist)); dist[1][0] = 0; queue<Node> q; q.push(Node(1, 0, 0)); while(!q.empty()){ Node t = q.front() ;q.pop(); int u = t.v; int p = t.p; for(int i=0; i<G[u].size() ;i++){ int v = G[u][i].v; int w = G[u][i].w; if(w > 0 && dist[v][p] > max(w, dist[u][p])){ dist[v][p] = max(w, dist[u][p]); q.push(Node(v, dist[v][p], p)); } else if(w == 0 && p != k && dist[v][p+1] > dist[u][p]){ dist[v][p+1] = dist[u][p]; q.push(Node(v, dist[v][p+1], p+1)); } } } } int main() { int n, m, k; cin>>n>>m>>k; for(int i=0; i<m ;i++){ int u, v, w; cin>>u>>v>>w; G[u].push_back(Edge(v, w)); G[u].push_back(Edge(v, 0)); G[v].push_back(Edge(u, w)); G[v].push_back(Edge(u, 0)); } spfa(n, k); int ans = inf; for(int i=k; i>=0 ;i--) ans = min(ans, dist[n][i]); if(ans != inf) cout<<ans; else cout<<-1; return 0; }