题意概括一下,就是在无向图上求一条1到n的路径,使路径上第k + 1大的边权尽量小。
考虑dp,令dp[i][j] 表示走到节点 i,路线上有 j 条电话线免费时,路径上最贵的电缆花费最小是多少。则对于一条从u到v,长度为w的边,转移方程是:
1.这条电缆要付费:dp[v][p] = min(dp[v][p], max(dp[u][p], w))
2.这条电缆免费:dp[v][p + 1] = min(dp[v][p +1], dp[u][p])
不过这是在图上dp,转移不能保证无后效性,因此我们可以利用spfa或dijkstra使dp有一个合理的顺序,因为最短路算法跑出来的是一个DAG,而dp状态之间的转移实质上就是在一个DAG上转移。
因为spfa他死了,所以我就用dijkstra写:考虑当前的“最短路”,不是单纯的dis,而是当前最优的dp[i][j],因此我们要开一个结构体优先队列,里面有dp[i][j], i 和 j。然后按dp[i][j]排序。
另外朴素的dijkstra是如果节点u出队了就不在入队,然而这道题需要开两维,in[i][j]表示节点 i ,j 个电话线免费的这个状态是否出队过。
具体看代码吧,挺好懂。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 1e3 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) {last = ch; ch = getchar();} 25 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 26 if(last == '-') ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) x = -x, putchar('-'); 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + '0'); 34 } 35 36 int n, p, k; 37 vector<int> v[maxn], c[maxn]; 38 39 struct Node 40 { 41 int _dp, nod, p; 42 bool operator < (const Node& other)const 43 { 44 return _dp > other._dp; 45 } 46 }; 47 int dp[maxn][maxn]; 48 bool in[maxn][maxn]; 49 50 void dijkstra(int s) 51 { 52 for(int i = 1; i <= n; ++i) 53 for(int j = 0; j <= n; ++j) dp[i][j] = INF; 54 dp[s][0] = 0; 55 priority_queue<Node> q; 56 q.push((Node){dp[s][0], s, 0}); 57 while(!q.empty()) 58 { 59 int now = q.top().nod, p = q.top().p; q.pop(); 60 if(in[now][p]) continue; 61 in[now][p] = 1; 62 for(int i = 0; i < (int)v[now].size(); ++i) 63 { 64 int to = v[now][i]; 65 if(dp[to][p] > max(dp[now][p], c[now][i])) 66 { 67 dp[to][p] = max(dp[now][p], c[now][i]); 68 q.push((Node){dp[to][p], to, p}); 69 } 70 if(p < k && dp[to][p + 1] > dp[now][p]) 71 { 72 dp[to][p + 1] = dp[now][p]; 73 q.push((Node){dp[to][p + 1], to, p + 1}); 74 } 75 } 76 } 77 write(dp[n][k] == INF ? -1 : dp[n][k]); enter; 78 } 79 80 int main() 81 { 82 n = read(); p = read(); k = read(); 83 for(int i = 1; i <= p; ++i) 84 { 85 int x = read(), y = read(), co = read(); 86 v[x].push_back(y); c[x].push_back(co); 87 v[y].push_back(x); c[y].push_back(co); 88 } 89 dijkstra(1); 90 return 0; 91 }