uva10801

题目链接请戳 这里 

 

解题思路

用Dijkstra或者SPFA解决。

主要问题是怎么建图和怎么处理换乘。

1.建图

对于每部电梯,经过的楼层两两都要连接,且有回边。

2.判断换乘

每条边上记录所用时间和用的哪部电梯。用一个数组choice[]保存每次到达楼层时之前乘坐的电梯,

对于楼层0需要特判。其实我觉得这个choice[]数组类似于用于打印最短路径的父指针数组fa[]。

有了这个数组,换乘就简单了,如果选择的路径的电梯于之前的电梯不同,那要判断:d[v[e]] > d[x] + w[e] + 60

如果相同,那么只需要判断:d[v[e]] > d[x] + w[e].

 

代码

Dijkstra和SPFA都只用了0ms,因为数据本来就不强。

首先是Dijkstra算法的代码

#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<stdlib.h>
#define N 110
#define M 20000
#define INF 1e9
using namespace std;

typedef pair<int, int> pii;
int u[M], v[M], nex[M], first[M], w[M], s[M];
int d[N], cost[N];
priority_queue <pii, vector<pii>, greater<pii> > q;
int n, k, m, choice[N], a[N];
char c[500];

void addedge(int x, int y, int l)
{
    u[m] = x; v[m] = y;
    w[m] = cost[l] * abs(y - x); s[m] = l;
    nex[m] = first[u[m]];
    first[u[m]] = m;
    m++;
    u[m] = y; v[m] = x;
    w[m] = cost[l] * abs(y - x); s[m] = l;
    nex[m] = first[u[m]];
    first[u[m]] = m;
    m++;
}

int dijkstra()
{
    for (int i = 0; i < N; i++) d[i] = INF; d[0] = 0;
    memset(choice, 0, sizeof(choice));
    q.push(make_pair(d[0], 0));
    while (!q.empty()) {
        pii u = q.top(); q.pop();
        int x = u.second; int now_choice = choice[u.second];
        if (u.first != d[x]) continue;
        for (int e = first[x]; e != -1; e = nex[e]) {
            if ((now_choice == 0 || s[e] == now_choice) && d[v[e]] > d[x] + w[e]) {
                d[v[e]] = d[x] + w[e];
                q.push(make_pair(d[v[e]], v[e]));
                choice[v[e]] = s[e];
            }
            else if( s[e] != now_choice && d[v[e]] > d[x] + w[e] + 60) {
                d[v[e]] = d[x] + w[e] + 60;
                q.push(make_pair(d[v[e]], v[e]));
                choice[v[e]] = s[e];
            }
        }
    }
    return d[k];
}

void solve()
{
    while (~scanf("%d%d", &n, &k)) {
        for (int i = 1; i <= n; i++) scanf("%d", &cost[i]);
        getchar();
        for (int i = 0; i < N; i++) first[i] = -1; 
        m = 0;
        for (int i = 1; i <= n; i++) {
            int num = 0;
            gets(c); char *p = c;
            while (*p != '\0') { 
                sscanf(p, "%d", &a[num++]); 
                while(*p != ' ' && *p != '\0') p++; 
                if (*p == ' ') p++; 
            }
            for (int j = 0; j < num - 1; j++)
                for (int k = j + 1; k < num; k++) 
                    addedge(a[j], a[k], i);
        }
        int ans = dijkstra();
        if (ans == INF) printf("IMPOSSIBLE\n");
        else printf("%d\n", ans);
    }
}

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

 

然后是SPFA。从Dijkstra改为SPFA很简单。把优先队列改为普通队列,且增加一个数组来判断节点是否在队列中。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<stdlib.h>
#define N 110
#define M 20000
#define INF 1e9
using namespace std;

typedef pair<int, int> pii;
int u[M], v[M], nex[M], first[M], w[M], s[M];
int d[N], cost[N];
queue <int> q;
int inq[N];
int n, k, m, choice[N], a[N];
char c[500];

void addedge(int x, int y, int l)
{
    u[m] = x; v[m] = y;
    w[m] = cost[l] * abs(y - x); s[m] = l;
    nex[m] = first[u[m]];
    first[u[m]] = m;
    m++;
    u[m] = y; v[m] = x;
    w[m] = cost[l] * abs(y - x); s[m] = l;
    nex[m] = first[u[m]];
    first[u[m]] = m;
    m++;
}

int SPFA()
{
    for (int i = 0; i < N; i++) d[i] = INF; d[0] = 0;
    memset(choice, 0, sizeof(choice));
    memset(inq, 0, sizeof(inq));
    q.push(0); inq[0] = true;
    while (!q.empty()) {
        int x = q.front(); q.pop();
        int now_choice = choice[x];
        inq[x] = false;
        for (int e = first[x]; e != -1; e = nex[e]) {
            if ((now_choice == 0 || s[e] == now_choice) && d[v[e]] > d[x] + w[e]) {
                d[v[e]] = d[x] + w[e];
                if (!inq[v[e]]) {
                    q.push(v[e]); inq[v[e]] = true;
                }
                choice[v[e]] = s[e];
            }
            else if( s[e] != now_choice && d[v[e]] > d[x] + w[e] + 60) {
                d[v[e]] = d[x] + w[e] + 60;
                if (!inq[v[e]]) {
                    q.push(v[e]); inq[v[e]] = true;
                }
                choice[v[e]] = s[e];
            }
        }
    }
    return d[k];
}

void solve()
{
    while (~scanf("%d%d", &n, &k)) {
        for (int i = 1; i <= n; i++) scanf("%d", &cost[i]);
        getchar();
        for (int i = 0; i < N; i++) first[i] = -1; 
        m = 0;
        for (int i = 1; i <= n; i++) {
            int num = 0;
            gets(c); char *p = c;
            while (*p != '\0') { 
                sscanf(p, "%d", &a[num++]); 
                while(*p != ' ' && *p != '\0') p++; 
                if (*p == ' ') p++; 
            }
            for (int j = 0; j < num - 1; j++)
                for (int k = j + 1; k < num; k++) 
                    addedge(a[j], a[k], i);
        }
        int ans = SPFA();
        if (ans == INF) printf("IMPOSSIBLE\n");
        else printf("%d\n", ans);
    }
}

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

 

posted @ 2016-11-08 19:31  啊嘞  阅读(257)  评论(0编辑  收藏  举报