ACM_JLINE.

二分+最短路

字数统计: 659阅读时长: 3 min
2019/01/24 Share

Telephone Lines

原题链接:Poj3662

题目大意 : 在无向图上求出一条从 1 到 N 的路径,是路径上第 K + 1 大的边权尽量小

  • 解法一: 仿造了动态规划的思想,D[x, y] 表示从1号节点到达基站x,途中已经指定了p条电缆免费时,经过的路径上最贵的电缆的花费最小是多少。那么对于x到y的长度为z的无向边,如果在(x,y,z)上不免费升级,那么可以用 max(D[x, p], z) 更新D[y, p]的最小值;如果在 (x, y, z) 免费升级,可以用 D[x, p] 更新 D[y, p+1] 的最小值。需要借助SPFA经行动态规划,直到所有状态收敛。复杂度为O(tNP)。个人觉得十分巧妙,太精辟了,有没有同感。
  • 解法二: 二分答案。问题也就可以理解为是否存在一种合理的升级方法,使花费不超过 mid。把图转成0 1 图,把一次最短路,与 K 经行比较即可。(转 0 1 图的时候不要新构造图,看代码就懂)

Code block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h>
#define pii pair<int, int>
#define FAST_IO ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;

const int INF = 0x3f3f3f3f;
const int Maxn = 1e3+5;
struct node{
int to, w;
};
vector <node> V[Maxn];
int n, m, k;
int Dis[Maxn], Vis[Maxn];
priority_queue <pii, vector<pii>, greater<pii> > q;

int Dij(int mid)
{
memset(Vis, 0, sizeof(Vis));
memset(Dis, INF, sizeof(Dis));
Dis[1] = 0;
q.push(pii(0,1));
while(q.size())
{
int x = q.top().second;
q.pop();
if(Vis[x]) continue;
Vis[x] = 1;
for(int i = 0; i < V[x].size(); i++)
{
int y = V[x][i].to, w = (V[x][i].w >= mid); //构造0 1
if(Dis[y] > Dis[x] + w){
Dis[y] = Dis[x] + w;
q.push(pii(Dis[y],y));
}
}
}
return Dis[n];
}
int main()
{
FAST_IO;
while(cin >> n >> m >> k)
{
int x, y, z; int Max = 0;
for(int i = 0; i <= n; i++) V[i].clear();
for(int i = 0; i < m; i++)
{
cin >> x >> y >> z;
Max = max(Max, z);
V[x].push_back((node){y, z});
V[y].push_back((node){x, z});
}
int ans = 0, l = 0, r = Max;
while(l <= r)
{
int mid = (l+r) / 2;
if(Dij(mid) <= k){
r = mid - 1;
}
else {
// cout << ans << endl;
ans = mid;
l = mid + 1;
}
}
if(l > Max) cout << -1 << endl;
else cout << ans << endl;
}
return 0;
}

然后因为寒假集训,坚持每天写写博客,确实虽然教的内容较难,但学到很多,重要的是作息十分规律,跟平时自己上学反差很大,教工食堂的饭菜也挺好。

CATALOG
  1. 1. Telephone Lines
    1. 1.0.1. Code block