二分+SPFA--poj3662

本文探讨了如何以最小成本将农民约翰的农场通过电话线路连接到电话系统,利用二分查找和SPFA算法求解最短路径问题,确保在限定的免费电缆长度内找到最优解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Language:
Telephone Lines
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 4397 Accepted: 1607

Description

Farmer John wants to set up a telephone line at his farm. Unfortunately, the phone company is uncooperative, so he needs to pay for some of the cables required to connect his farm to the phone system.

There are N (1 ≤ N ≤ 1,000) forlorn telephone poles conveniently numbered 1..N that are scattered around Farmer John's property; no cables connect any them. A total of P (1 ≤ P ≤ 10,000) pairs of poles can be connected by a cable; the rest are too far apart.

The i-th cable can connect the two distinct poles Ai and Bi, with length Li (1 ≤ Li ≤ 1,000,000) units if used. The input data set never names any {AiBi} pair more than once. Pole 1 is already connected to the phone system, and pole N is at the farm. Poles 1 and need to be connected by a path of cables; the rest of the poles might be used or might not be used.

As it turns out, the phone company is willing to provide Farmer John with K (0 ≤ K < N) lengths of cable for free. Beyond that he will have to pay a price equal to the length of the longest remaining cable he requires (each pair of poles is connected with a separate cable), or 0 if he does not need any additional cables.

Determine the minimum amount that Farmer John must pay.

Input

* Line 1: Three space-separated integers: NP, and K
* Lines 2..P+1: Line i+1 contains the three space-separated integers: AiBi, and Li

Output

* Line 1: A single integer, the minimum amount Farmer John can pay. If it is impossible to connect the farm to the phone company, print -1.

Sample Input

5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6

Sample Output

4

思路:二分答案然后构图,比mid小的边权值为0,否则为,1,然后求最短路,如果比K大,则返回false,否则韩慧true。
下面是代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAX=11000;
const int INF=100000;
struct node
{
    int to,len,next;
}edge[MAX];
int pre[1010],dis[1010];
bool vis[1010];
int N,P,K;
int num;
int a[MAX],b[MAX],f[MAX];
void init()
{
    memset(pre,-1,sizeof(pre));
    num=0;
}
void add_edge(int a,int b,int f)
{
    edge[num].to=b;
    edge[num].next=pre[a];
    edge[num].len=f;
    pre[a]=num++;
    edge[num].to=a;
    edge[num].next=pre[b];
    edge[num].len=f;
    pre[b]=num++;
}
void build(int mid)
{
    init();
    for(int i=0;i<P;i++)
    {
        if(f[i]>mid)
            add_edge(a[i],b[i],1);
        else
            add_edge(a[i],b[i],0);
    }
}
bool spfa()
{
    for(int i=1;i<=N;i++)
    {
        vis[i]=false;
        dis[i]=INF;
    }
    queue<int> q;
    q.push(1);
    dis[1]=0;
    vis[1]=true;
    while(!q.empty())
    {
        int t=q.front();
        vis[t]=false;
        q.pop();
        for(int i=pre[t];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dis[v]>dis[t]+edge[i].len)
            {
                dis[v]=dis[t]+edge[i].len;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=true;
                }
            }
        }
    }
    if(dis[N]>K)
        return false;
    return true;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(cin>>N>>P>>K)
    {
        //init();
        int max1=0;
        for(int i=0;i<P;i++)
        {
            scanf("%d%d%d",&a[i],&b[i],&f[i]);
            if(f[i]>max1)
                max1=f[i];
        }
        int l=0,r=max1,mid;
        while(r>l)
        {
            mid=(l+r)/2;
            build(mid);
            bool flag=spfa();
            if(dis[N]==INF)
            {
                l=-1;
                break;
            }
            if(flag)
                r=mid;
            else
                l=mid+1;
        }
        cout<<l<<endl;
    }
    return 0;
}


<think>好的,我需要回答用户关于Bellman-Ford算法和SPFA的实现与比较的问题。首先,我得回顾一下这两个算法的基本概念和原理。Bellman-Ford算法是用来解决单源最短路径问题的,可以处理带有负权边的图,而SPFA(队列优化的Bellman-Ford)是对其的一种优化,通过减少不必要的松弛操作来提高效率。 接下来,我需要确保按照用户提供的系统级指令来组织内容。首先,所有的行内数学公式要用$...$,比如时间复杂度O(VE)应该写成$O(VE)$。独立公式需要用$$...$$并且单独成段,比如松弛操作的公式可能需要单独列出。 然后,需要检查LaTeX语法是否正确,比如积分符号\int和上下标是否正确。同时,使用中文回答,并且生成相关问题。用户还提到在引用的段落末尾添加引用标识,这里参考的引用[1]是关于SPFA的优化,需要在适当的地方插入[^1]。 用户的问题包括实现和比较,所以需要分别给出Bellman-Ford和SPFA的代码示例。Bellman-Ford的Python实现通常包括遍历所有边进行松弛操作,而SPFA则使用队列来维护需要松弛的节点,减少重复计算。在代码部分要注意格式,使用三个反引号包裹代码块,并标明语言为python。 在比较部分,需要列出时间复杂度、空间复杂度、适用场景以及各自的优缺点。比如Bellman-Ford的时间复杂度是$O(VE)$,而SPFA的平均情况下是$O(E)$,最坏情况下还是$O(VE)$。同时,SPFA在稀疏图上表现更好,但在存在负权环的情况下需要检测机制。 最后生成的相关问题要围绕算法差异、SPFA的优化、负权环检测以及应用场景展开。确保每个问题都有针对性,能够帮助用户进一步理解这两个算法。 现在需要整合所有内容,确保结构清晰,分步骤解释Bellman-Ford和SPFA的实现,然后进行比较。同时,正确引用提供的参考内容,特别是在讨论SPFA优化时,添加[^1]的引用标识。还要检查数学公式的格式是否正确,比如松弛操作的公式是否使用行内或独立格式,以及代码示例是否符合要求。 可能需要注意的细节包括:Bellman-Ford是否能检测负权环,SPFA如何检测,以及在实际代码中如何处理这些情况。例如,Bellman-Ford通过第V次松弛是否还能更新来判断,而SPFA通过记录节点的入队次数是否超过V-1次。 最后,确保生成的相关问题与内容相关,并且能够引导用户深入探索,比如询问优化方法、性能比较、检测负权环的方法等。</think>### Bellman-Ford算法与SPFA对比分析 #### 1. Bellman-Ford算法实现 **核心思想**:通过$V-1$轮对所有边的松弛操作,逐步逼近最短路径值。能检测负权环(若第$V$轮仍能松弛则存在负权环)。 **时间复杂度**:$O(VE)$ **适用场景**:含负权边的图、需检测负权环的场景 ```python def bellman_ford(graph, start): n = len(graph) distance = [float('inf')] * n distance[start] = 0 for _ in range(n-1): for u, v, w in graph.edges: if distance[u] + w < distance[v]: distance[v] = distance[u] + w # 检测负权环 for u, v, w in graph.edges: if distance[u] + w < distance[v]: return "存在负权环" return distance ``` #### 2. SPFA实现(队列优化) **优化原理**:使用队列存储需要松弛的节点,避免无效松弛。只有当某个节点的最短距离更新时,才将其相邻节点加入队列。 **时间复杂度**:平均$O(E)$,最坏仍为$O(VE)$ **适用场景**:稀疏图、无负权环的图 ```python def spfa(graph, start): n = len(graph) distance = [float('inf')] * n in_queue = [False] * n counter = [0] * n # 检测负权环 queue = deque() distance[start] = 0 queue.append(start) in_queue[start] = True while queue: u = queue.popleft() in_queue[u] = False for v, w in graph.adj[u]: if distance[u] + w < distance[v]: distance[v] = distance[u] + w if not in_queue[v]: queue.append(v) in_queue[v] = True counter[v] += 1 if counter[v] > n-1: return "存在负权环" return distance ``` #### 3. 关键对比 | 特性 | Bellman-Ford | SPFA | |---------------------|-----------------------|----------------------| | **时间复杂度** | $O(VE)$ | 平均$O(E)$,最坏$O(VE)$ | | **空间复杂度** | $O(V)$ | $O(V+E)$ | | **负权处理** | 支持 | 支持但需额外检测 | | **实现复杂度** | 简单 | 中等 | | **适用场景** | 稠密图/强检测需求 | 稀疏图/高效场景 | #### 4. 数学原理 松弛操作公式: $$d[v] = \min(d[v], d[u] + w(u,v))$$ SPFA的优化体现在通过队列维护更新节点集合,减少冗余计算。该优化基于动态逼近理论,只有当$d[u]$发生变化时,$u$的后继节点才可能需要进行松弛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值