P1218 过路费

  奋斗了两天,终于写过了这道题......

  这道题不仅要求最短路,还要加上路径上最大的点权;

  先用结构体记录点的序号和点的值这是毋庸置疑的;再用另外一个数组来记录当前点权也是可以理解的,毕竟后面要排序;将点权从小到大排序也是为了求最短路;然后再输入每条边的权值;min是为了保证两点之间有重复的边而取最小值;n代表两边的最小值,l就加上了点权;Floyd先将两点相同时就是自己的点权;将点权从小到大枚举,用t来记录此时所对应的原来的序号;两边之间的最短路就用普通的方法,加上点权就要加上中间量k值的点权和两端i,j点权的最大值;最后输出就行了;

#include <bits/stdc++.h>

using namespace std;

inline int read() {
    int x = 0,ff = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') ff = -1;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x<<1) + (x<<3) + (ch ^ 48);
        ch = getchar();
    }
    return x * ff;
}

inline void write(int x) {
    if(x < 0) putchar('-'),x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int a,b,c,m[1111],n[1100][1100],l[1010][1010];

struct node {
    int id;
    int v;
} d[1111];

bool my(node x,node y) {
    return x.v < y.v;
}

void Floyd() {
    for(int i = 1; i <= a; ++i)
        l[i][i] = m[i];
    for(int k = 1; k <= a; ++k) {
        int t = d[k].id;
        for(int i = 1; i <= a; ++i) {
            for(int j = 1; j <= a; ++j) {
                n[i][j] = min(n[i][j],n[i][t] + n[t][j]);
                l[i][j] = min(l[i][j],n[i][j] + max(d[k].v,max(m[i],m[j])));
            }
        }
    }
}

int main() {
    memset(n,0x3f,sizeof(n));
    memset(l,0x3f,sizeof(l));
    a = read();
    b = read();
    c = read();
    for(int i = 1; i <= a; ++i) {
        d[i].v = read();
        d[i].id = i;
        m[i] = d[i].v;
    }
    sort(d + 1,d + a + 1,my);
    for(int i = 1; i <= b; ++i) {
        int x,y,v;
        x = read();
        y = read();
        v = read();
        n[x][y] = min(n[x][y],v);
        n[y][x] = min(n[y][x],v);
    }
    Floyd();
    for(int i = 1; i <= c; ++i) {
        int x,y;
        x = read();
        y = read();
        write(l[x][y]);
        putchar('
');
    }


    return 0;
}

原文地址:https://www.cnblogs.com/AK-ls/p/10103888.html