CodeForces - 95C Volleyball(建边+dij)

传送门

题意:n个路口m条边,每一个路口都有一辆出租车,给你每辆出租车的能经过的最大长度和花费,给你一个起点一个终点问你从起点到终点最少要多少钱。

题解:先用dij跑出每个点到另外点的最小距离,再枚举两个点的连线,如果满足d[i][j]<=i点出租车的最大长度则建边,最后再跑一次自己建的图

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <queue>
#define se second
#define fi first
#define Pli pair<ll,int>
#define fio ios::sync_with_stdio(false);cin.tie(0)
const int N=1e6+5e3;
const ll INF=0x3f3f3f3f3f3f3f3f;
using namespace std;
int head[N];
int to[N];
ll val[N];
int nx[N];
ll dis[1005][1005];
int tot=1;
void add(int u,int v,ll w){
    to[tot]=v;
    val[tot]=w;
    nx[tot]=head[u];
    head[u]=tot++;
}
priority_queue<Pli,vector<Pli>,greater<Pli> >q;
int n,m;
bool done[N];
ll len[N],c[N];
ll ans[N];
void dij(int n,int x,ll *dis ){
    for(int i=1;i<=n;i++)dis[i]=INF,done[i]=0;
    dis[x]=0;q.push({0,x});
    while(!q.empty()){
        Pli p=q.top();
        q.pop();
        int u=p.se;
        ll dd=p.fi;
        for(int i=head[u];i;i=nx[i]){
            int v=to[i];
            if(dis[v]>dd+val[i]){
                dis[v]=dd+val[i];
                q.push({dis[v],v});
            }
        }
    }
}
int main(){
    scanf("%d %d",&n,&m);
    int s,t;
    scanf("%d %d",&s,&t);
    while(m--){
        int u,v;
        ll w;
        scanf("%d%d%lld",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    for(int i=1;i<=n;i++){
        dij(n,i,dis[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&len[i],&c[i]);
    }
    tot=1;
    memset(head, 0,sizeof(head));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            else if(dis[i][j]<=len[i])add(i,j,c[i]);
        }
    }
    dij(n,s,ans);
    if(ans[t]!=INF)cout<<ans[t]<<endl;
    else cout<<-1<<endl;
    return 0;
}

 

posted @ 2018-04-02 09:55  采蘑菇的小西佬  阅读(106)  评论(0编辑  收藏  举报