电话网络

[题目描述]
由于地震使得连接汶川县城电话线全部损坏,假如你是负责将电话线接到震中汶川县城的负责人,汶川县城周围分布着N(1≤N≤1,000)根按1..N 顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相连。一共P(1≤P≤10,000)对电话线杆间可以拉电话线,其余的由于地震使得无法被连接。

第i 对电话线杆的两个端点分别为Ai,Bi,它们间的距离为Li(1≤Li≤1,000,000)。数据中保证每对(Ai,Bi)最多只出现1 次。编号为1 的电话线杆已经接人了全国的电话网络,整个县城的电话线全都连到了编号为N 的电话线杆上。也就是说,你的任务仅仅是找一条将1 号和N 号电话线杆连起来的路径,其余的电话线杆并不一定要连人电话网络。
电信公司决定支援灾区免费为汶川县城连结K(0≤K<N)对由你指定的电话线杆。对于此外的那些电话线,需要为它们付费,总费用等于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过K 对,那么总支出为0。
请你计算一下,将电话线引到震中汶川县城最少需要在电话线上花多少钱?


[输入格式]
输入文件的第一行包含三个用空格隔开的整数:N,P 和K。
第二行到第P+1 行:每行分别都为空格隔开的整数:Ai,Bi 和Li。


[输出格式]
输出文件中仅包含一个整数,表示在这项工程上的最小支出。如果任务不可能完成,则输出-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


[输出样例]
4

 

 

凭着个人做题经验,关于图的问题大多是最短路,最小生成树,网络流等等。只不过题会给你出的面目全非,让你看不出算法是啥,所以这时候呢,我们就想办法往自己学过的算法上靠。

(以上仅代表自己想的)

 

可以用二分的方法。二分答案,然后对于每一次二分得到的答案,将图中所有大于这个数的边的边权设为1,否则设为0。这样图就变成了一个边权只有0和1的图了。

然后再跑一遍最短路。得到的1到n节点的距离如果大于k,就说明我们要让电信公司连接的电线杆多了,也就是说这个答案小了,于是在右子区间里找;否则就在左子区间里找。

 

我觉得这个算法的精妙之处是在于转化成最短路的想法:就是边权变为0或1,这样跑最短路的时候就统计出了比ans大的边有几条,进而继续二分。

 

乍一看最短路的定义改成了路径上边权最大的边最小,但最终还是一个普通的最短路。所以可见最短路这个算法是一个很成熟的算法,或说是一个固定的算法。我们要去做的不是去更改这个算法,而是想办法将其他问题转化成可以用这个算法解决的问题。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream> 
  5 #include<cstring>
  6 #include<cmath>
  7 #include<vector>
  8 #include<queue>
  9 #include<cctype>    //isdigit 
 10 using namespace std;
 11 typedef long long ll;
 12 #define enter printf("\n")
 13 const int maxn = 1e4 + 5;
 14 const int INF = 0x3f3f3f3f;
 15 inline ll read()
 16 {
 17     ll ans = 0;
 18     char ch = getchar(), last = ' ';
 19     while(!isdigit(ch)) {last = ch; ch = getchar();}
 20     while(isdigit(ch))
 21     {
 22         ans = ans * 10 + ch - '0'; ch = getchar();    
 23     }
 24     if(last == '-') ans = -ans;
 25     return ans;
 26 }
 27 inline void write(ll x)
 28 {
 29     if(x < 0) {putchar('-'); x = -x;}
 30     if(x == 0) {putchar('0'); return;}
 31     int q[100], N = 0;
 32     q[1] = 0;
 33     while(x) {q[++N] = x % 10; x /= 10;}
 34     while(N) {putchar('0' + q[N]); --N;}
 35 }
 36 
 37 int n, P, k;
 38 int p[maxn];
 39 void init(int n)
 40 {
 41     for(int i = 1; i <= n; ++i) p[i] = i;
 42 }
 43 int Find(int x)
 44 {
 45     return x == p[x] ? x : p[x] = Find(p[x]);
 46 }
 47 void merge(int x, int y)
 48 {
 49     int px = Find(x), py = Find(y);
 50     if(px == py) return;
 51     p[px] = py; return;
 52 }
 53 
 54 vector<int> v[maxn], c[maxn];
 55 struct Node
 56 {
 57     int x, y, co;
 58 }edges[maxn];
 59 int dis[maxn];
 60 bool done[maxn];
 61 void init_(int n)
 62 {
 63     for(int i = 1; i <= n; ++i) 
 64     {
 65         v[i].clear(); c[i].clear();
 66         dis[i] = done[i] = 0;
 67     }
 68 }
 69 bool check(int x)
 70 {
 71     init_(n);
 72     for(int i = 1; i <= P; ++i)
 73     {
 74         if(edges[i].co > x)
 75         {
 76             v[edges[i].x].push_back(edges[i].y); c[edges[i].x].push_back(1);
 77             v[edges[i].y].push_back(edges[i].x); c[edges[i].y].push_back(1);
 78         }
 79         else
 80         {
 81             v[edges[i].x].push_back(edges[i].y); c[edges[i].x].push_back(0);    
 82             v[edges[i].y].push_back(edges[i].x); c[edges[i].y].push_back(0);        
 83         }
 84     }
 85     for(int i = 1; i <= n; ++i) dis[i] = INF;
 86     queue<int> q; q.push(1);
 87     done[1] = 1; dis[1] = 0; 
 88     while(!q.empty())
 89     {
 90         int now = q.front(); q.pop(); done[now] = 0;
 91         for(int i = 0; i < (int)v[now].size(); ++i)
 92         {
 93             if(dis[now] + c[now][i] < dis[v[now][i]])
 94             {
 95                 
 96                 dis[v[now][i]] = dis[now] + c[now][i];
 97                 if(!done[v[now][i]])
 98                 {
 99                     q.push(v[now][i]);
100                     done[v[now][i]] = 1;
101                 }
102             }
103         }
104     }
105     return dis[n] <= k ? true : false;
106 }
107 int Max = 0;
108 
109 int main()
110 {
111     freopen("phone.in", "r", stdin);
112     freopen("phone.out", "w", stdout);
113     n = read(); P = read(); k = read();
114     if(P <= k) {printf("0\n"); return 0;}
115     init(n);
116     for(int i = 1; i <= P; ++i) 
117     {
118         edges[i].x = read(), edges[i].y = read(), edges[i].co = read();
119         merge(edges[i].x, edges[i].y);
120         Max = max(Max, edges[i].co);
121     }
122     if(Find(1) != Find(n)) {printf("-1\n"); return 0;}        //并查集判断一下图的连通性 
123     int L = 0, R = Max;
124     while(L < R)
125     {
126         int mid = (L + R) >> 1;
127         if(check(mid)) R = mid;
128         else L = mid + 1;
129     }
130     write(L); enter;
131     return 0;
132 }

 

上一篇:685. 冗余连接 II(有向图中找环-dfs)


下一篇:Kruskal模板——并查集实现