您的位置:首页 > 理论基础 > 计算机网络

洛谷 1948 笨笨的电话网络

2015-10-25 20:13 393 查看

题目描述 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.

输入样例:

[code]5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6


输出样例:

[code]4


这题有两种做法,按出题人的想法应该是二分+spfa验证,然而因为k数值较小,可以跑一次分层图的spfa水过去233。

二分+spfa验证:

二分最少在电话线上花的钱 mid,遍历一遍边,边的权值大于mid,就把权值设为 1,其余设为 0,然后从起点跑最短路,这时到终点的最短路的意义是连接 1 到 n 需要花 dist
对超过 mid 花费的电线,显然,dist
超过 k 时二分的答案是不科学的,借这个判断就好了。

分层图:

把dist数组开成二维,利用dp的思想dist[i][j] 表示用了 j 次免费的机会到 连接到 i 点的最大值spfa松弛操作时有两种选择:用或不用免费机会 , 当然用的话一定要当前使用次数 < k 才好。

二分 + spfa验证代码:

[code]#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
 > 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
 == 0x3f3f3f3f)
    {
        puts("-1");
        return 0;
    }
    cout<<EF(1,p);
    return 0;
}


分层图 + spfa代码:

[code]#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
[k] >= 214748364)
        puts("-1");
    else
        printf("%d",dist
[k]);
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: