洛谷 1948 笨笨的电话网络

来源:互联网 发布:ipad翻墙用什么软件 编辑:程序博客网 时间:2024/05/27 16:42

题目描述 Description

多年以后,笨笨长大了,成为了电话线布置师。由于地震使得某市的电话线全部损坏,笨笨是负责接到震中市的负责人。该市周围分布着N(1<=N<=1000)根据1……n顺序编号的废弃的电话线杆,任意两根线杆之间没有电话线连接,一共有p(1<=p<=10000)对电话杆可以拉电话线。其他的由于地震使得无法连接。
第i对电线杆的两个端点分别是ai,bi,它们的距离为li(1<=li<=1000000)。数据中每对(ai,bi)只出现一次。编号为1的电话杆已经接入了全国的电话网络,整个市的电话线全都连到了编号N的电话线杆上。也就是说,笨笨的任务仅仅是找一条将1号和N号电线杆连起来的路径,其余的电话杆并不一定要连入电话网络。
电信公司决定支援灾区免费为此市连接k对由笨笨指定的电话线杆,对于此外的那些电话线,需要为它们付费,总费用决定于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。如果需要连接的电话线杆不超过k对,那么支出为0.
请你计算一下,将电话线引导震中市最少需要在电话线上花多少钱?

输入格式:

输入文件的第一行包含三个数字n,p,k;
第二行到第p+1行,每行分别都为三个整数ai,bi,li。

输出格式:

一个整数,表示该项工程的最小支出,如果不可能完成则输出-1.

输入样例:

5 7 11 2 53 1 42 4 83 2 35 2 93 4 74 5 6

输出样例:

4

这题有两种做法,按出题人的想法应该是二分+spfa验证,然而因为k数值较小,可以跑一次分层图的spfa水过去233。
二分+spfa验证:
二分最少在电话线上花的钱 mid,遍历一遍边,边的权值大于mid,就把权值设为 1,其余设为 0,然后从起点跑最短路,这时到终点的最短路的意义是连接 1 到 n 需要花 dist[n] 对超过 mid 花费的电线,显然,dist[n] 超过 k 时二分的答案是不科学的,借这个判断就好了。
分层图:
把dist数组开成二维,利用dp的思想dist[i][j] 表示用了 j 次免费的机会到 连接到 i 点的最大值spfa松弛操作时有两种选择:用或不用免费机会 , 当然用的话一定要当前使用次数 < k 才好。

二分 + spfa验证代码:

#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;const int size = 200010;int head[size],next[size],dist[size];bool use[size];int dis[size],rr[size];int n,p,k;struct dc{    int t,d;} l[size];int tot = 1;void build(int f,int t,int d){    l[tot].t = t;    l[tot].d = d;    next[tot] = head[f];    head[f] = tot ++;}queue < int > q;void spfa(){    memset(dist,63,sizeof(dist));    dist[1] = 0;    use[1] = 1;    q.push(1);    while(!q.empty())    {        int f = q.front();        q.pop();        use[f] = 0;        for(int i = head[f] ; i ; i = next[i])        {            int t = l[i].t;            if(dist[t] > dist[f] + dis[i])            {                dist[t] = dist[f] + dis[i];                if(!use[t])                {                    use[t] = 1;                    q.push(t);                }            }        }    }}bool check(int mid){    for(int i = 1 ; i < tot ; i ++)        if(l[i].d > mid)            dis[i] = 1;        else            dis[i] = 0;    spfa();    if(dist[n] > k)        return false;    return true;}int EF(int l,int r){    while(r - l > 1)    {        int mid = (l + r) >> 1;        if(!check(rr[mid]))            l = mid;        else            r = mid;    }    return rr[r];}int main(){    scanf("%d%d%d",&n,&p,&k);    for(int i = 1 ; i <= p ; i ++)    {        int f,t,d;        scanf("%d%d%d",&f,&t,&d);        build(f,t,d);        build(t,f,d);        rr[i] = d;    }    sort(rr+1,rr+p+1);    spfa();    if(dist[n] == 0x3f3f3f3f)    {        puts("-1");        return 0;    }    cout<<EF(1,p);    return 0;}

分层图 + spfa代码:

#include<iostream>#include<cstdio>#include<queue>using namespace std;const int size = 20010;int head[size],next[size],dist[size][11];bool use[size][11];int n,m,k;int tot = 1;queue < int > q;struct dc{    int t,d;}l[size];void build(int f,int t,int d){    l[tot].t = t;    l[tot].d = d;    next[tot] = head[f];    head[f] = tot ++;}void spfa(){    for(int i = 1 ; i <= n ; i ++)        for(int j = 0 ; j <= k ; j ++)            dist[i][j] = 214748364;    dist[1][0] = 0;    use[1][0] = 1;    q.push(1);    q.push(0);    while(!q.empty())    {        int f = q.front();        q.pop();        int time = q.front();        q.pop();        use[f][time] = 0;        for(int i = head[f] ; i ; i = next[i])        {            int t = l[i].t;            if(dist[t][time] > max(dist[f][time],l[i].d)) //dist[t][time] > max(dist[f][time],l[i].d)            {                dist[t][time] = max(dist[f][time],l[i].d);                if(!use[t][time])                {                    use[t][time] = 1;                    q.push(t);                    q.push(time);                }            }            if(time < k)            {                if(dist[t][time+1] > dist[f][time])                {                    dist[t][time+1] = dist[f][time];                    if(!use[t][time+1])                    {                        use[t][time+1] = 1;                        q.push(t);                        q.push(time+1);                    }                }            }        }    }}int main(){    scanf("%d%d%d",&n,&m,&k);    for(int i = 1 ; i <= m ; i ++)    {        int f,t,d;        scanf("%d%d%d",&f,&t,&d);        build(f,t,d);        build(t,f,d);    }    spfa();    if(dist[n][k] >= 214748364)        puts("-1");    else        printf("%d",dist[n][k]);    return 0;}
0 0
原创粉丝点击