Cf163#2 problem D
http://codeforces.com/contest/266/problem/D
这是一道最短路的题目,比赛的时候想到最短路算法,也想到二分,但细节还是没想清楚,导致挂了。。
后来比赛完之后感觉2分有问题,
就想到三分法,然后写了下,一直没法ac。。(而且也担心时间问题),最后还是用二分ac之。。
最初枚举边,把边断掉,边的两端点各做一遍的spfa,对于结果点进行3分枚举(因为其满足单峰,也就是满足类似抛物线形)
然后去最小值与当前最优答案比较,更优着替换。
发现这样第9点就TLE了。。。因为条边都要做一遍的spfa,时间复杂度太高了(实际上没必要每次用spfa)
所以今天就改为先用floyd处理出任意两点间的最短距离mindist,在做三分。。。然后不知道怎么回事还是挂了(这个算法是没错的,因为有人这样3分过了)。。
再来说说后来发现最开始的2分法是可行的,但操作上有点变化。。
2分具体实现:1、 2分最大答案dist,然后判定
2、 然后判定在当前dist下,第各个点经过dist所能到覆盖到当前枚举边的范围
3、 对这些范围求公共区域,如果存在,则为合法解,否则不合法(即求解多个不等式)
4、根据返回的结果再二分,返回到1
注意:该题的结果不是不是整数就是含有0.5(因为所有的边都为整数,/2也就只有可能出现0.5,不会出现其他形式的小数),所以可以对边进行*2,变成整数操作。。做完ans/2.0即可。。。
写这道题收获还是蛮多的,感觉挺拓宽思路的。。
Code:
1 /* 2 * Status: solve 3 * User: Yzcstc 4 * Resources: Codeforces 163#2 D 5 * Typical: Shortest paths 6 * Time: 2013.01.24 7 */ 8 #include <iostream> 9 #include <fstream> 10 #include <cstring> 11 #include <cstdio> 12 #include <cstdlib> 13 #include <string> 14 #include <algorithm> 15 #include <vector> 16 #define INF 1000000000 17 #define MAXN 210 18 using namespace std; 19 struct edge{ int x , y , z; }; 20 struct oo{ int l,r ; }; 21 edge a[40000]; 22 oo b[MAXN]; 23 int n , m , d[MAXN][MAXN]; 24 double ans; 25 void init(){ 26 int x , y , z; 27 scanf("%d",&n); 28 scanf("%d",&m); 29 for (int i = 1; i <= n; ++i) 30 for (int j = 1; j <= n; ++j) 31 if (i != j) d[i][j] = INF; 32 33 for (int i = 1; i <= m; ++i){ 34 scanf("%d%d%d",&x,&y,&z); 35 z <<= 1; 36 d[x][y] = d[y][x] = z; 37 a[i].x = x; 38 a[i].y = y; 39 a[i].z = z; 40 } 41 } 42 43 void floyd(){ 44 for (int k = 1; k <= n; ++k) 45 for (int i = 1; i <= n; ++i) 46 for (int j = 1; j <= n; ++j) 47 d[i][j] = min( d[i][j] , d[i][k] + d[k][j] ); 48 } 49 50 bool cmp(const oo a, const oo b){ 51 if (a.l<b.l || a.l == b.l && a.r < b.r ) return true; 52 return false; 53 } 54 55 int check(int dist){ 56 int tm , d1 , d2 , x , y , z , LL; 57 bool flag; 58 for (int i = 1; i <= m; ++i){ 59 x = a[i].x; 60 y = a[i].y; 61 z = a[i].z; 62 LL = 0; 63 flag = true; 64 for (int j = 1; j <= n ; ++j){ 65 d1 = dist - d[x][j]; 66 d2 = dist - d[y][j]; 67 if (d1 >= z || d2 >= z) continue; 68 if (d1 + d2 >= z) continue; 69 if (d1 <0 && d2 <0 ) { 70 flag = false; 71 break; 72 } 73 ++LL; 74 b[LL].l = d1; 75 b[LL].r = z - d2; 76 } 77 if (flag){ 78 if (!LL) return 1; 79 sort( b+1, b+LL+1 ,cmp); 80 tm = 0; 81 for (int j = 1; j <= LL; ++j){ 82 if (tm <= b[j].l) return 1; 83 if (tm < b[j].r) tm = b[j].r; 84 } 85 } 86 87 } 88 return 0; 89 } 90 91 void solve(){ 92 int l = 0, r = 2*INF, mid; 93 while (r - l > 1){ 94 mid = (l + r) >> 1; 95 if (check(mid)) r = mid; 96 else l = mid; 97 } 98 if (check(l)) ans = l; 99 else ans = r; 100 printf("%0.1lf\n", ans / 2.0); 101 } 102 103 int main(){ 104 freopen("d.in","r",stdin); 105 freopen("d.out","w",stdout); 106 init(); 107 floyd(); 108 solve(); 109 }
浙公网安备 33010602011771号