• 电话网络


    [题目描述]
    由于地震使得连接汶川县城电话线全部损坏,假如你是负责将电话线接到震中汶川县城的负责人,汶川县城周围分布着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("
    ")
     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
    "); 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
    "); 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 }
  • 相关阅读:
    让footer始终位于页面的最底部
    javascript拼接html代码
    vs2010 sp1安装
    jquery call 函数改变this作用域
    复选框选中提示车牌号正则表达式
    hibernate Session一级缓存 应该注意的地方
    整理的一些java中常使用jar包以及说明
    springmvc 生命周期
    struts2之constant 讲解 (转)
    装饰器模式
  • 原文地址:https://www.cnblogs.com/mrclr/p/9054128.html
Copyright © 2020-2023  润新知