hdu 3499 flight 【分层图】+【Dijkstra】

<题目链接>

题目大意:

现在给你一些点,这些点之间存在一些有向边,每条边都有对应的边权,有一次机会能够使某条边的边权变为原来的1/2,求从起点到终点的最短距离。

解题分析:

分层图最短路模板题,由于最多只能将一条边变成原来的1/2,所以我们在原来二维的图形上多加一层,由第一层到第二层的边代表该边边权为原边权的1/2。就按这种思想跑一遍Dijkstra即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <iostream>
using namespace std;

typedef long long ll;
#define INF 1e18
const int N=1e5+7;
const int M=5e5+7;
int n,m,cnt,head[N];
bool vis[N][2];

struct DEGE{
    int to,next;
    ll val;
}edge[M];
struct NODE{
    int loc,level;
    ll dis;
    bool operator <(const NODE &tmp)const{
        return dis>tmp.dis;
    }
    NODE(int a=0,int b=0,ll c=0){
        loc=a,level=b,dis=c;
    }
}d[N][2];
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
}
void add(int u,int v,ll w){
    edge[++cnt].to=v,edge[cnt].val=w;
    edge[cnt].next=head[u],head[u]=cnt;
}
void dij(int st){
    for(int i=1;i<=n;i++){
        for(int j=0;j<=1;j++)
            d[i][j].dis=INF;       //将所有点到起点的距离置为无穷
    }
    d[st][0].dis=0;
    priority_queue<NODE>q;
    q.push(NODE(st,0,0));
    while(!q.empty()){
        NODE now = q.top();
        q.pop();
        int tmp1=now.loc,tmp2=now.level;
        if(vis[tmp1][tmp2])continue;
        vis[tmp1][tmp2]=true;
        for(int i=head[tmp1];~i;i=edge[i].next){
            int v=edge[i].to;
            ll cost =edge[i].val;
            if(d[v][tmp2].dis>d[tmp1][tmp2].dis+cost){
                d[v][tmp2].dis=d[tmp1][tmp2].dis+cost;
                q.push(NODE(v,tmp2,d[v][tmp2].dis));
            }
            if(tmp2==0&&d[v][tmp2+1].dis>d[tmp1][tmp2].dis+cost/2){  //如果tmp1---->v之间的边变成原来值的1/2
                d[v][tmp2+1].dis=d[tmp1][tmp2].dis+cost/2;
                q.push(NODE(v,tmp2+1,d[v][tmp2+1].dis));
            }
        }
    }
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        map<string,int>mpa;
        init();
        int tot=0;
        string st,ed;ll w;
        for(int i=1;i<=m;i++){
            cin>>st>>ed>>w;
            if(!mpa[st])mpa[st]=++tot;    //如果这个字符串没有出现过,就给它编号
            if(!mpa[ed])mpa[ed]=++tot;
            add(mpa[st],mpa[ed],w);   //建立有向边
        }
        cin>>st>>ed;
        if(m==0){printf("-1
");continue;}
        dij(mpa[st]);
        ll ans=min(d[mpa[ed]][0].dis,d[mpa[ed]][1].dis);
        ans==INF?printf("-1
"):printf("%lld
",ans);
    }
    return 0;
}

2018-09-24