拉电线:N个电线杆P条线可选,K条线内免费,否则花费免费额度外最长的那一根。求最小花费。
3.1不光是查找值!“二分搜索”
最小化第k大的值
Dijkstra结合二分解决,题还行,是谁写了这么蠢的题干,出来我保证不打死你。“the phone company is willing to provide Farmer John with K (0 ≤ K < N) lengths of cable for free.”这句话的正确理解是,K条线免费,长度任意;而不是一条长度为K的电线。这是解题的关键,出题人写完题目没有考虑英语渣渣的感受,length of是一根的意思,lengths of就是复数根的意思……英语渣伤不起
下面看看怎么把它转换成最短路问题:
设mid为某条线的长度,长于mid的线放到免费额度里,否则自己掏钱。如果存在一个临界值x,使得长于x的电线数量恰好等于K,这个临界值对应的解就是最优解。如何计算长于mid的电线数量呢?排序比较肯定不行的,因为不知道这条电线用不用得上。所以需要Dijkstra,又因为在mid固定的条件下,电线的花费只取决于长度是否大于mid,所以可以将大于的取为1,小于的取为0。这样花费就可以计算了,并且花费等于长于mid的电线数量,也就是需要自己掏钱的电线的数量。
二分条件敲定了之后就是普通的二分问题了,假定长度mid以下的都免费,对长度二分。当二分结束的时候,就到达了临界状态“花钱与不花钱的临界”,此状态就是答案了。
#include <iostream> #include <queue> #include <vector> #include <functional> using namespace std; #define MAX_V 1000 + 16 #define MAX_L 1000000 // 从顶点from指向顶点to的权值为cost的边 struct edge { int to, cost; edge(){} edge(int to, int cost) : to(to), cost(cost){} }; // first 最短路径,second顶点编号 typedef pair<int, int> P; // 边 vector<edge> G[MAX_V]; // 最短距离 int d[MAX_V]; // V是顶点数,E是边数 int V, E; // 求解从顶点s出发到所有点的最短距离 // x表示x单位之内免费 // 返回需要的电线数量 int dijkstra_ex(int s, int x) { priority_queue<P, vector<P>, greater<P> > que; memset(d, 0x3f, V * sizeof(int)); d[s] = 0; que.push(P(0, s)); while (!que.empty()) { P p = que.top(); que.pop(); int v = p.second; if (d[v] < p.first) continue; for (int i = 0; i < G[v].size(); ++i) { edge e = G[v][i]; int new_d = d[v] + (e.cost >= x ? 1 : 0); if (d[e.to] > new_d) { d[e.to] = new_d; que.push(P(d[e.to], e.to)); } } } return d[V - 1]; } ///////////////////////////SubMain////////////////////////////////// int main(int argc, char *argv[]) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int K; cin >> V >> E >> K; for (int i = 0; i < E; ++i) { int from, to, cost; cin >> from >> to >> cost; --from; --to; G[from].push_back(edge(to, cost)); G[to].push_back(edge(from, cost)); } int lb = 0, ub = MAX_L + 2; while (ub - lb > 1) { int mid = (ub + lb) >> 1; if (dijkstra_ex(0, mid) > K) {// mid 太取小了 lb = mid; } else { ub = mid; } } cout << (lb > MAX_L ? -1 : lb) << endl; #ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout); system("out.txt"); #endif return 0; } ///////////////////////////End Sub//////////////////////////////////
12848537 | hankcs | 3662 | Accepted | 516K | 297MS | C++ | 1799B | 2014-05-07 14:21:07 |
知识共享署名-非商业性使用-相同方式共享:码农场 » POJ 3662 Telephone Lines 题解 《挑战程序设计竞赛》
图论弱的一笔
我去,怪不得我样例手算都算不出!!!