Divide and conquer:Telephone Lines(POJ 3662)

                

                电话线

  题目大意:一堆电话线要你接,现在有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
");
 67             return;
 68         }
 69     }
 70     printf("%d
", 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 }

原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5143826.html