1. 程式人生 > >【洛谷P1491】集合位置

【洛谷P1491】集合位置

題目大意:求給定的一張無向帶權圖的次短路。

題解:先跑一遍 spfa 求出從起點到終點的最短路,記錄路徑。接著列舉刪邊,並重新跑 spfa,統計最小值即可。
至於為什麼 dp 做法不行,暫時還不清楚。

程式碼如下

#include <bits/stdc++.h>
using namespace std;
const int maxe=2e4+10;
const int maxv=210;
const double inf=0x3f3f3f3f;

struct node{
    int nxt,to;
    double w;
}e[maxe<<1];
int tot=1,head[maxv];
inline void add_edge(int from,int to,double w){
    e[++tot]=node{head[from],to,w},head[from]=tot;
}
int n,m,pre[maxv];
double x[maxv],y[maxv],d[maxv],ans=inf;
bool in[maxv];

inline double calc(int a,int b){
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}

void read_and_parse(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
    for(int i=1,a,b;i<=m;i++){
        scanf("%d%d",&a,&b);
        double c=calc(a,b);
        add_edge(a,b,c),add_edge(b,a,c);
    }
}

queue<int> q;

void spfa(int a,int b){
    memset(in,0,sizeof(in));
    fill(d+1,d+n+1,inf);
    q.push(1),in[1]=1,d[1]=0;
    while(q.size()){
        int u=q.front();q.pop(),in[u]=0;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;double w=e[i].w;
            if((u==a&&v==b)||(v==a&&u==b))continue;
            if(d[v]>d[u]+w){
                d[v]=d[u]+w;
                if(a==-1&&b==-1)pre[v]=u;
                if(!in[v])q.push(v),in[v]=1;
            }
        }
    }
}

void solve(){
    spfa(-1,-1);
    for(int i=n;pre[i];i=pre[i]){
        spfa(i,pre[i]);
        ans=min(ans,d[n]);
    }
    if(ans==inf)puts("-1");
    else printf("%.2lf\n",ans);
}

int main(){
    read_and_parse();
    solve();
    return 0;
}