[HDU1595] find the longest of the shortest

题目链接:

点我

题意:

给定一个\(n\)个点,\(m\)条边的带权无向图,起点为\(1\),终点为\(n\),现在可以删去其中的一条边,求一种删边方案使得剩下图的最短路值最大,输出这个最短路的长度。
题目保证删去任意一条边都能使得\(1\)\(n\)连通,且边权均为正值。

题目分析:

首先用\(Dijkstra\)跑出原图的最短路,由于在最短路之外删边对图的最短路没有影响,所以考虑在最短路上删边,直接暴力跑\(Dijkstra\)
需要注意的是,这里不会超时的原因是一个有\(n\)个点的正权无向图的最短路总共包含的边数不会超过\(n-1\)。最坏的情况是把每个点都经过一遍,这样就会有\(n-1\)条边在最短路上,而如果最短路的边数\(>n-1\),就说明有节点被经过了两遍,(既然要从这里第二次经过,为什么还要到外面绕一圈而不是直接走呢?)这和最短路矛盾,而在实际情况中,最短路的边数甚至远远达不到这个上界。所以在最短路上删边暴力跑\(Dij\)的最坏时间复杂度是\(O(n*log(n)+n^2*log(n))\)

代码:

#include<bits/stdc++.h>
#define N (1000+5)
#define M (1000000+5)
using namespace std;
priority_queue< pair<int,int> > q;
inline int read(){
    int cnt=0,f=1;char c;
    c=getchar();
    while(!isdigit(c)){
        if(c=='-') f=-f;
        c=getchar();
    }
    while(isdigit(c)){
        cnt=cnt*10+c-'0';
        c=getchar();
    }
    return cnt*f;
}
int n,m,first[N],nxt[M],to[M],w[M],d[N],tot,a,b,v,ans=-1;
bool vis[N];
int path[N];
void add(int x,int y,int z) { 
    nxt[++tot]=first[x];
    first[x]=tot;
    to[tot]=y;
    w[tot]=z;
}

void dijkstra(){
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[1]=0;
    q.push(make_pair(0,1));
    while(q.size()) {
        int u=q.top().second; q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(register int i=first[u];i;i=nxt[i]) {
            int v=to[i];int z=w[i];
            if(d[v]>d[u]+z) {
                d[v]=d[u]+z;
                path[v]=u;
                q.push(make_pair(-d[v],v));
            }
        }
    }
}

void dijkstra2(int x,int y) {
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[1]=0;
    q.push(make_pair(0,1));
    while(q.size()) {
        int u=q.top().second; q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(register int i=first[u];i;i=nxt[i]) {
            int v=to[i];int z=w[i];
            if((u==x&&v==y)||(u==y&&v==x))continue;
            if(d[v]>d[u]+z) {
                d[v]=d[u]+z;
                q.push(make_pair(-d[v],v));
            }
        }
    }
}

int main(){
    while(scanf("%d%d",&n,&m)!=EOF) {
        tot=0;
        for(register int i=1;i<=n;i++) path[i]=-1;
        for(register int i=1;i<=n;i++) first[i]=0;
        ans=-1;
        for(register int i=1;i<=m;i++) {
            a=read();b=read();v=read();
            add(a,b,v);add(b,a,v);
        }
        dijkstra();
        for(register int i=n;i!=-1;i=path[i]) {
//            cout<<i<<" "<<path[i]<<endl;
            dijkstra2(i,path[i]);
            ans=max(ans,d[n]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kma093/p/10387907.html