UVA 10801 Lift Hopping (最短路)

最短路问题,不过起点不只是1个,终点也不止1个,因此把不同电梯的楼层分别编号,相邻楼层之间连边,不同电梯的相同楼层之间连边。

dij的时候一次性把所有起点压到队列中,如果直接套版可以加一超级源点s和所有起点连一条dist为0的边。

需要维护的信息:

为了判断之前电梯有没有出现相同楼层,需要维护一个楼层到点编号的映射,为了判断终点,需要维护点编号到楼层的映射。

#include<bits/stdc++.h>
using namespace std;

int n,k;

const int maxn = 100;
typedef long long ll;

vector<int> lift[5];
int id[5][maxn]; //判断出现 和 换乘
int flrId[5*maxn]; //结点对应的楼层,判断终点用
int sp[5];//speed

#define PB push_back

struct Edge
{
    int v,w;
};
int vcnt; //结点编号从1开始

vector<Edge> edges;
vector<int> G[maxn*5+1];

void addEdge(int u,int v,int w)
{
    G[u].PB(edges.size());
    edges.PB({v,w});
}

void AddEdge(int u,int v,int w)
{
    addEdge(u,v,w);
    addEdge(v,u,w);
}

const ll INF = 0x3f3f3f3f3f3f3f3fLL;
ll d[maxn];
typedef pair<int,int> Node;
#define fi first
#define se second

ll dijkstra(int tflr = k)
{
    fill(d+1,d+1+vcnt,INF);
    priority_queue<Node,vector<Node>,greater<Node> > q;
    for(int i = 0; i < n; i++) if(id[i][0]){
        q.push(Node(0,id[i][0])); d[id[i][0]] = 0;
    }
    while(q.size()){
        Node x = q.top(); q.pop();
        int u = x.se;
        if(flrId[u] == tflr) return d[u];
        if(d[u] != x.fi) continue;
        for(int i = 0; i < G[u].size(); i++){
            Edge &e = edges[G[u][i]];
            if(d[e.v] > d[u] + e.w){
                d[e.v] = d[u] + e.w;
                q.push(Node(d[e.v],e.v));
            }
        }
    }
    return INF;
}



bool sscan_l(int &x,char *&s)//非负数
{
    while(!isdigit(*s)){
        if(!*s) return false;
        s++;
    }
    x = *s-'0';
    while(s++,isdigit(*s)) x = x*10+*s-'0';
    return true;
}

char str[233];
void read()
{
    for(int i = 0; i < n; i++) scanf("%d",sp+i);
    scanf("\n");
    for(int i = 0; i < n; i++) {
        gets(str); char *p = str;
        int floor; lift[i].clear();
        while(sscan_l(floor,p)){
            lift[i].PB(floor);
        }
    }
}

void buildGraph()
{
    for(int i = 0; i < n; i++){
        int sz = lift[i].size();
        if(sz){
            int flr = lift[i][0];
            id[i][flr] = ++vcnt;
            flrId[vcnt] = flr;
            G[vcnt].clear();
            for(int k = 0; k < i; k++) if(id[k][flr]){
                AddEdge(vcnt,id[k][flr],60);
            }

            for(int j = 1; j < sz; j++){
                flr = lift[i][j];
                id[i][flr] = ++vcnt;
                flrId[vcnt] = flr;
                G[vcnt].clear();
                for(int k = 0; k < i; k++) if(id[k][flr]){
                    AddEdge(vcnt,id[k][flr],60);
                }

                int cost = (flr-lift[i][j-1])*sp[i];
                AddEdge(vcnt-1,vcnt,cost);
            }
        }
    }
}

void init()
{
    memset(id,0,sizeof(id));
    vcnt = 0;
    edges.clear();
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&k)){
        init();
        read();
        buildGraph();
        ll ans = dijkstra();
        if(ans<INF){
            printf("%lld\n",ans);
        }else puts("IMPOSSIBLE");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/jerryRey/p/4769522.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值