poj 1135 最短路(优先队列堆优化Dijkstra实现)

Problem: http://poj.org/problem?id=1135

求图中距离1点最远(包括点和边上的点)的距离

先对所有点求单源(点1)最短路

然后每条边上的点距离1点最远的距离必为边两端点到点1的最短距离和该边的长度 三者和的一半

现在点到源(点1)的距离知道了 边到源(点1)的距离也知道了 只需要比较两者了

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define MAXN 510
#define MAXE 250010
int n,m,size,head[MAXN],A[MAXE],B[MAXE],pre[MAXN];
double C[MAXE],dist[MAXN];
bool vis[MAXN];
struct Edge{
    int to,next;
    double w;
}e[MAXE<<1];
void add_edge(int u,int v,double w){//链式前向星存图 
    e[size].to=v;
    e[size].w=w;
    e[size].next=head[u];
    head[u]=size++;
}
void Seap(int &a,int &b){
    int c=a;
    a=b;
    b=c;
}
void work(int s){
    for(int i=1;i<=n;i++)dist[i]=-1;
    memset(vis,false,sizeof(vis));
    dist[s]=0;
    priority_queue<pair<double,int> > heap;//优先队列实现堆 
    heap.push(make_pair(0,s));
    while(!heap.empty()){//堆优化Dijkstra 
        int u=heap.top().second;
        heap.pop();
        if(vis[u])continue;
        vis[u]=true;
        int k=head[u];
        while(k>=0){
            if(dist[e[k].to]<0 || dist[e[k].to]>dist[u]+e[k].w){
                pre[e[k].to]=u;
                dist[e[k].to]=dist[u]+e[k].w;
                heap.push(make_pair(-dist[e[k].to],e[k].to));
            }
            k=e[k].next;
        }
    }
    int k1,k2;
    double ans1=0,ans2=0;
    for(int i=1;i<=n;i++){//求距源最远的点 
        if(dist[i]>ans1){
            ans1=dist[i];
            k1=i;
        }
    }
    for(int i=0;i<m;i++){//求距源最远的边 
        double l=dist[A[i]]+dist[B[i]]+C[i];
        if(l/2>ans2){
            ans2=l/2;
            k2=i;
        }
    }
    printf("The last domino falls after ");

    if(ans1>=ans2)printf("%.1f seconds, at key domino %d.
",ans1,k1);
    else{
        if(A[k2]>B[k2])Seap(A[k2],B[k2]);
        printf("%.1f seconds, between key dominoes %d and %d.
",ans2,A[k2],B[k2]);
    }
}
void init(){
    size=0;
    memset(head,-1,sizeof(head));
    for(int i=0;i<m;i++){
        scanf("%d%d%lf",&A[i],&B[i],&C[i]);
        add_edge(A[i],B[i],C[i]);
        add_edge(B[i],A[i],C[i]);
    }
}
int main(){
    int t=0;
    while(scanf("%d%d",&n,&m),n+m){
        init();
        printf("System #%d
",++t);
        work(1);
        printf("
");
    }
    return 0;
}
View Code

题中边长l没给范围是个坑,直接用double是明智滴真知>>>>>.<<<<<<

原文地址:https://www.cnblogs.com/cshhr/p/3545070.html