[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;
}
posted @ 2020-08-12 15:39  Jayun  阅读(107)  评论(0编辑  收藏  举报