1. 程式人生 > >bzoj1614: [Usaco2007 Jan]Telephone Lines架設電話線(二分答案 + spfa)

bzoj1614: [Usaco2007 Jan]Telephone Lines架設電話線(二分答案 + spfa)

原題連結

題目描述:FarmerJohn打算將電話線引到自己的農場,但電信公司並不打算為他提供免費服務。於是,FJ必須為此向電信公司支付一定的費用。FJ的農場周圍分佈著N(1<=N<=1,000)根按1..N順次編號的廢棄的電話線杆,任意兩根電話線杆間都沒有電話線相連。一共P(1<=P<=10,000)對電話線杆間可以拉電話線,其餘的那些由於隔得太遠而無法被連線。第i對電話線杆的兩個端點分別為A_i、B_i,它們間的距離為L_i(1<=L_i<=1,000,000)。資料中保證每對{A_i,B_i}最多隻出現1次。編號為1的電話線杆已經接入了全國的電話網路,整個農場的電話線全都連到了編號為N的電話線杆上。也就是說,FJ的任務僅僅是找一條將1號和N號電話線杆連起來的路徑,其餘的電話線杆並不一定要連入電話網路。經過談判,電信公司最終同意免費為FJ連結K(0<=K<N)對由FJ指定的電話線杆。對於此外的那些電話線,FJ
需要為它們付的費用,等於其中最長的電話線的長度(每根電話線僅連結一對電話線杆)。如果需要連結的電話線杆不超過K對,那麼FJ的總支出為0。請你計算一下,FJ最少需要在電話線上花多少錢。

輸入格式:第1行: 3個用空格隔開的整數:N,P,以及K
第2..P+1行: 第i+1行為3個用空格隔開的整數:A_i,B_i,L_i

輸出格式:第1行: 輸出1個整數,為FJ在這項工程上的最小支出。
如果任務不可能完成, 輸出-1

輸入樣例
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
輸入說明:
一共有5根廢棄的電話線杆。電話線杆1不能直接與電話線杆4、5相連。電話
線杆5不能直接與電話線杆1、3相連。其餘所有電話線杆間均可拉電話線。電信
公司可以免費為FJ連結一對電話線杆。

輸出樣例
4
輸出說明:
FJ選擇如下的連結方案:1->3;3->2;2->5,這3對電話線杆間需要的
電話線的長度分別為4、3、9。FJ讓電信公司提供那條長度為9的電話線,於是,
他所需要購買的電話線的最大長度為4。

解析:首先二分答案,再來考慮如何判斷是否可行。
   對於二分出的值x,比x小的長度可以看作0,比x大的長度可以看作1,再從1~n跑一遍最短路。
   如果最短的長度小於等於k,那麼可行;否則不可行。

程式碼如下:

#include<cstdio>
#include<queue>
using namespace std;

const int maxn = 1005;
int n, p, k, vis[maxn], dis[maxn];
int hed[maxn * 20], nxt[maxn * 20], to[maxn * 20], val[maxn * 20], cnt;
queue <int> que;

int read(void) {
    char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0';
    while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x;
}

void add(int x, int y, int v) {
    nxt[++ cnt] = hed[x]; hed[x] = cnt; to[cnt] = y; val[cnt] = v;
}

int spfa(int x) {
    que.push(1);
      for (int i = 1; i <= n; ++ i) dis[i] = 2e9;
    dis[1] = 0; vis[1] = 1;
      while (!que.empty()) {
        int u = que.front(); vis[u] = 0; que.pop();
          for (int i = hed[u]; i ; i = nxt[i]) {
              int v = to[i];
                if (dis[v] > dis[u] + (val[i] > x)) {
                      dis[v] = dis[u] + (val[i] > x);
                      if (!vis[v]) {
                            vis[v] = 1;
                            que.push(v);
                          }
                    }
            }
      }
    if (dis[n] > k) return 0; else return 1;
}

int main() {
    n = read(); p = read(); k = read();
      for (int i = 1; i <= p; ++ i) {
        int x = read(), y = read(), v = read();
        add(x, y, v); add(y, x, v);
      }
    int l = 0, r = 1000000, mid, res = -1;
      while (l <= r) {
        mid = l + r >> 1;
          if (spfa(mid)) r = mid - 1, res = mid;
            else l = mid + 1;
      }
    printf("%d", res);
    return 0;
}