标签:
题目大意:一堆电话线要你接,现在有N个接口,总线已经在1端,要你想办法接到N端去,电话公司发好心免费送你几段不用拉网线,剩下的费用等于剩余最长电话线的长度,要你求出最小的费用。
这一看又是一个最小化最大值的问题(也可以看成是最大化最小值的问题),常规方法一样的就是把这个费用二分就好,但是这道题是道图论题,不一定经过所有的点,那我们就以二分基准长度为界限,把小于基准长度的那一部分看成是0,大于等于基准长度的看成是1,这样我们只用SPFA算法算最短路径就可以了,非常的巧妙
参考:http://poj.org/showmessage?message_id=181794
PS:好久没写SPFA了,都忘记是怎么写了,重新定义长度的时候又忘记乘以2了WA一个晚上真是日了
1 #include <iostream> 2 #include <algorithm> 3 #include <functional> 4 #define SIZE 1010 5 6 using namespace std; 7 typedef int Position; 8 9 struct _set 10 { 11 Position ed; 12 int next; 13 int length; 14 }Path[20005]; 15 struct _head 16 { 17 int point; 18 }Heads[SIZE]; 19 static int dist[SIZE]; 20 static bool visit[SIZE], oep[20005]; 21 static Position que[(SIZE + 1) * 2]; 22 23 void solve(const int, const int, const int, const int); 24 bool SPFA(const int, const int, const int, const int); 25 26 int main(void) 27 { 28 int Sum_Poles, Free_Cables, Sum_Path, length, L_Max; 29 Position st, ed; 30 31 while (~scanf("%d%d%d", &Sum_Poles, &Sum_Path, &Free_Cables)) 32 { 33 L_Max = -1; 34 for (int i = 0; i <= Sum_Poles; i++) 35 Heads[i].point = -1; 36 for (int i = 0; i < 2 * Sum_Path;) 37 { 38 scanf("%d%d%d", &st, &ed, &length); 39 //无向图,两边都要存 40 Path[i].ed = ed; Path[i].length = length; Path[i].next = Heads[st].point; 41 Heads[st].point = i++; 42 43 Path[i].ed = st; Path[i].length = length; Path[i].next = Heads[ed].point; 44 Heads[ed].point = i++; 45 46 L_Max = max(L_Max, length); 47 } 48 solve(Sum_Poles, Sum_Path, Free_Cables, L_Max); 49 } 50 return 0; 51 } 52 53 void solve(const int Sum_Poles, const int Sum_Path, const int Free_Cables, const int L_Max) 54 { 55 int lb = 0, rb = L_Max + 1, mid; 56 57 while (rb - lb > 1)//对距离二分 58 { 59 mid = (lb + rb) >> 1; 60 if (SPFA(mid, Sum_Path, Sum_Poles, Free_Cables)) lb = mid; 61 else rb = mid; 62 if (dist[Sum_Poles] == 0x3fffffff) 63 //任何一次寻找过后,如果图能到N点,那么N的dist值一定不是0x3fffffff 64 //否则,一定是不联通 65 { 66 printf("-1\n"); 67 return; 68 } 69 } 70 printf("%d\n", lb); 71 } 72 73 bool SPFA(const int x, const int Sum_Path, const int Sum_Poles, const int Free_Cables) 74 { 75 int head = 0, back = 1, out, to; 76 77 que[head] = 1; //开始是从1开始的 78 79 for (int i = 0; i < 2 * Sum_Path; i++) 80 oep[i] = Path[i].length < x ? 0 : 1; 81 82 fill(dist, dist + Sum_Poles + 1, 0x3fffffff); 83 memset(visit, 0, sizeof(visit)); 84 dist[1] = 0; 85 86 while (head != back) 87 { 88 out = que[head]; head = (head + 1) % (2 * SIZE); 89 visit[out] = 0; 90 91 for (int k = Heads[out].point; k != -1; k = Path[k].next) 92 { 93 to = Path[k].ed; 94 if (dist[out] + oep[k] < dist[to]) 95 { 96 dist[to] = dist[out] + oep[k]; 97 if (!visit[to]) 98 { 99 visit[to] = 1; 100 que[back] = to; back = (back + 1) % (2 * SIZE); 101 } 102 } 103 } 104 } 105 return dist[Sum_Poles] > Free_Cables; 106 }
Divide and conquer:Telephone Lines(POJ 3662)
标签:
原文地址:http://www.cnblogs.com/Philip-Tell-Truth/p/5143826.html