pku 3662 Telephone Lines 二分+Dijkdtra
http://poj.org/problem?id=3662
开始读这个题目的直接理解错了题意,没想到lengths竟然还有几段的意思;题意求从1到n的每段路径下(除去k各最大的)最长最短问题。
一个无向图有n个点, m条边, 每边有花费val[i], 可以任意指定有k条边免费, 现要求选择若干条边构成顶点1到顶点n的一条路径, 使得路径上边权最大值(不包括免费边)最小.
二分答案, 重新建图, Dijkstra
感觉这个讲解比较详细:
我们暂且不考虑最优解的问题, 假设A为一个可行解. 可以知道如果A成立, 则B(B>=A)一定成立. 这说明解具有单调性, 即所有可行解是一个单调序列. 我们模仿二分查找的方法, 对答案进行二分尝试, 对最优解逐步逼近.
对于这道题, 假设A=4这个解成立, 则说明顶点1到N之间必存在某路径, 满足这条路径中长度大于4的边不超过K条(如果超过K条, 4就不是去除K条以外的最大值了, 与题意矛盾).
1. 判断给定的A是否为可行解, 即求从顶点1到顶点N的某条路径上, 长度大于A的边最少有多少条. 如果最少的条数小于等于K, 则A为一个可行解.
对于求最少的条数, 可以在原图的基础上构造一个新图, 改变边权. 如果一条边原来的权值大于A, 则在新图中将其权值设为1;如果一条边原来的权值小于等于A, 则在新图中将其权值设为0.
然后求出从顶点1到N的最短路径长度D, D即为从顶点1到顶点N的某条路径上, 长度大于A的边最少有多少条. 如果D<=K, 则A为可行解.
View Code
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 1007 #define inf 99999999 using namespace std; int map[maxn][maxn]; struct node { int x,y; int val; }p[maxn*10]; int n,m,k; int dis[maxn]; bool vt[maxn]; int cmp(node a,node b) { return a.val < b.val; } void init() { int i,j; for (i = 0; i <= n; ++i) { for (j = 0; j <= n; ++j) { if (i == j) map[i][j] = 0; else map[i][j] = inf; } } } void Dijkstra() { int i,j,min; for (i = 1; i <= n; ++i) { vt[i] = false; dis[i] = map[1][i]; } vt[1] = true; for (int ki = 1; ki < n; ++ki) { j = 1; min = inf; for (i = 2; i <= n; ++i) { if (!vt[i] && dis[i] < min) { j = i; min = dis[i]; } } if (min == inf) break; vt[j] = true; for (i = 2; i <= n; ++i) { if (!vt[i] && dis[i] > map[i][j] + dis[j] && map[i][j] != inf) { dis[i] = map[i][j] + dis[j]; } } } } int main() { //freopen("in.txt","r",stdin); int i; int x,y,z; scanf("%d%d%d",&n,&m,&k); init(); for (i = 1; i <= m; ++i) { scanf("%d%d%d",&x,&y,&z); map[x][y] = map[y][x] = 1; p[i].x = x; p[i].y = y; p[i].val = z; } //按边的权值排序 sort(p + 1, p + 1 + m, cmp); int l = 0, r = m - 1; int ms = 0,ans = -1; p[0].val = 0;//注意这里0的处理 while (l <= r) { int mid = (l + r)/2; //ms的左边都是0,右边都是1 if (ms <= mid) { for (i = ms; i <= mid; ++i) { map[p[i].x][p[i].y] = map[p[i].y][p[i].x] = 0; } } else { for (i = mid + 1; i <= ms; ++i) { map[p[i].x][p[i].y] = map[p[i].y][p[i].x] = 1; } } ms = mid; Dijkstra(); if (dis[n] > k) l = mid + 1; else { ans = mid; r = mid - 1; } } //printf("%d\n",ans); if (ans == - 1) printf("-1\n"); else printf("%d\n",p[ans].val); return 0; }