[USACO07JAN] 架设电话线
题目大意:
给定一个 \(n\) 个节点的无向图,从 \(1\) 出发到 \(n\) 的路径中,\(k\) 条路径长度可变为 \(0\),操作完后路径必须是最短的,问操作完后的最长路段长度。
正文:
最短路径中的最长路段,由此想到通过二分答案求解,二分一条线的权值 \(w\),\(w\) 作为最短路中最长路段的长度,大于 \(w\) 的长度就改为一,否则为零,最短路的长度如果大于 \(k\) 就不可行,小于等于 \(k\) 就可行。
代码:
int SPFA(int mid)
{
memset (dis, 60, sizeof(dis));
memset (vis, 0, sizeof(vis));
for (; !que.empty(); que.pop());
que.push(1);
vis[1] = 1;
dis[1] = 0;
while(!que.empty())
{
int x = que.front();
que.pop();
for (int i = head[x]; i; i = e[i].next)
{
int y = e[i].to;
if (dis[x] + (e[i].w > mid) < dis[y])
{
dis[y] = dis[x] + (e[i].w > mid);
if (!vis[y])
{
vis[y] = 1;
que.push(y);
}
}
}
vis[x] = 0;
}
if (dis[n] == dis[0]) return -1;
else if (dis[n] <= k) return 1;
else return 0;
}
int main()
{
scanf ("%lld%lld%lld", &n, &m, &k);
for (int i = 1; i <= m; i++)
{
ll u, v, w;
scanf ("%lld%lld%lld", &u, &v, &w);
add(u, v, w);
add(v, u, w);
val[i] = w;
}
sort (val + 1, val + 2 + m);
int l = 1, r = m + 1, mid;
while (l < r)
{
mid = (l + r) >> 1;
int check = SPFA(val[mid]);
if(check == -1){puts("-1");return 0;}
if(check) r = mid;
else l = mid + 1;
}
printf("%d", val[l]);
return 0;
}