图论专题III

[vijos 美食节]最小费用流

From:https://www.vijos.org/p/1726

Solution:

假设厨师i做菜品j做n次, 那么第k次做时对答案的贡献就是(n-k+1)*t[j][i]。我们把每个厨师进行拆点, 建图用费用流即可算出答案。但是这题图较大, 需要动态加边。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stack>
#include <functional>
using namespace std;
#define N 45
#define M 101
#define oo 0x6fffffff
#define nil (-1)
bool inQ[N*M];
struct {int c,w,to,next;} nod[20*N*M];
int adj[N*M], d[N*M], fa[N*M], idx[N*M], last[M], t[N][M], p[N], cnt[M], now, S, T;
void Init(int n){
    now = 0; S = 0; T = n+1;
    for (int i = 0; i <= T; ++i) adj[i] = nil;
}
int NewNode(int u, int w, int c){
    nod[now].to = u; nod[now].w = w; nod[now].c = c; nod[now].next = nil;
    return now++;
}
void AddEdge(int u, int v, int w, int c){
    int u1 = NewNode(v, w, c);
    int v1 = NewNode(u, -w, 0);
    nod[u1].next = adj[u]; adj[u] = u1;
    nod[v1].next = adj[v]; adj[v] = v1;
}
bool Spfa(int n){
    for (int i = 0; i <= n; ++i) d[i] = oo, fa[i] = nil, inQ[i] = false;
    queue<int> Q;
    d[S] = 0; Q.push(S); inQ[S] = true;
    while ( !Q.empty() ){
        int u = Q.front(); Q.pop(); inQ[u] = false;
        for (int i = adj[u]; i != nil; i = nod[i].next){
            int v = nod[i].to;
            if ( nod[i].c > 0 && d[v] > d[u] + nod[i].w ){
                d[v] = d[u] + nod[i].w;
                fa[v] = u; idx[v] = i;
                if ( !inQ[v] ) inQ[v] = true, Q.push(v);
            }
        }
    }
    return d[T] != oo;
}
int Argument(){
    int cf = oo;
    for (int i = T; i != S; i = fa[i]) cf = min(cf, nod[idx[i]].c);
    for (int i = T; i != S; i = fa[i]){
        nod[idx[i]].c -= cf; nod[idx[i]^1].c += cf;
    }
    return d[T];
}
int main()
{
    int n, m;
    while ( scanf("%d%d", &n, &m) != EOF ){
        int sp = 0;
        for (int i = 1; i <= n; ++i){
            scanf("%d", p+i);
            sp += p[i];
        }
        Init(n+m+sp);
        for (int i = 1; i <= n; ++i){
            AddEdge(S, i, 0, p[i]);
            for (int j = 1; j <= m; ++j){
                scanf("%d", &t[i][j]);
                AddEdge(i, n+j, t[i][j], 1);
            }
        }
        for (int j = 1; j <= m; ++j){
            AddEdge(n+j, T, 0, 1);
            last[j] = now-2; cnt[j] = 1;
        }
        int ans = 0;
        for (int k = 1; k <= sp && Spfa(n+m+sp+1); ++k){
            ans += Argument();
            int j = 1;
            for ( ; j <= m && nod[last[j]].c; ++j);
            ++cnt[j];
            for (int i = 1; i <= n; ++i){
                AddEdge(i, n+m+k, cnt[j]*t[i][j], 1);
            }
            AddEdge(n+m+k, T, 0, 1);
            last[j] = now-2;
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

 

[vijos 丛林探险]最短路

From:https://www.vijos.org/p/1082

Solution:

这道题有两个纬度, 体力和时间。丢弃任何一个纬度, 就变成简单的最短路径了。容易发现, 体力最短的不一定时间最短, 时间最短的不一定体力最短, 这提示我们需要记录到某个顶点u时的体力和对应的时间, 然后枚举。不妨记dp[i][0][0]是从源点到i时最少体力对应的(体力,时间)花费, dp[i][0][1]是从源点到i时最小时间对应的(体力,时间)花费, dp[i][1][0]是从汇点到i时最小体力对应的(体力,时间)花费, dp[i][1][1]是从汇点到i时最小时间对应的(体力,时间)花费。那么就会出现四种情况:

dp[i][0][0]+dp[i][1][0]: 从源到i的最小体力和从i到汇点的最小体力下的花费

dp[i][0][0]+dp[i][1][1]: 从源到i的最小体力和从i到汇点的最小时间下的花费

dp[i][0][1]+dp[i][1][0]: 从源到i的最小时间和从i到汇点的最小体力下的花费

dp[i][0][1]+dp[i][1][1]: 从源到i的最小时间和从i到汇点的最小时间下的花费

因此, 枚举点i, 即可算出从源到汇的满足体力限制的最小时间。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stack>
#include <functional>
using namespace std;
#define N 5005
#define M 40005
#define oo 0x6fffffff
#define nil (-1)
bool inQ[N];
struct {int c,w,to,next;} nod[M*2];
int adj[N], d[N], c[N], dp[N][2][2][2], now;
void Init(int n){
    now = 0;
    for (int i = 0; i <= n; ++i) adj[i] = nil;
}
int NewNode(int v, int c, int w){
    nod[now].to = v; nod[now].c = c; nod[now].w = w; nod[now].next = nil;
    return now++;
}
void AddEdge(int u, int v, int c, int d){
    int u1 = NewNode(v, c, d);
    nod[u1].next = adj[u]; adj[u] = u1;
}
void Spfa_w(int S, int n, bool fromT){
    for (int i = 0; i <= n; ++i) d[i] = oo, c[i] = 0, inQ[i] = false;
    queue<int> Q;
    d[S] = 0; inQ[S] = true; Q.push(S);
    dp[S][fromT][0][1] = dp[S][fromT][1][1] = 0;
    while ( !Q.empty() ){
        int u = Q.front(); Q.pop(); inQ[u] = false;
        for (int i = adj[u]; i != nil; i = nod[i].next){
            int v = nod[i].to;
            if ( d[v] > d[u] + nod[i].w ){
                d[v] = d[u] + nod[i].w;
                c[v] = c[u] + nod[i].c;
                dp[v][fromT][0][1] = c[v];
                dp[v][fromT][1][1] = d[v];
                if ( !inQ[v] ) inQ[v] = true, Q.push(v);
            }
        }
    }
}
void Spfa_c(int S, int n, bool fromT){
    for (int i = 0; i <= n; ++i) d[i] = 0, c[i] = oo, inQ[i] = false;
    queue<int> Q;
    c[S] = 0; inQ[S] = true; Q.push(S);
    dp[S][fromT][0][0] = dp[S][fromT][1][0] = 0;
    while ( !Q.empty() ){
        int u = Q.front(); Q.pop(); inQ[u] = false;
        for (int i = adj[u]; i != nil; i = nod[i].next){
            int v = nod[i].to;
            if ( c[v] > c[u] + nod[i].c ){
                c[v] = c[u] + nod[i].c;
                d[v] = d[u] + nod[i].w;
                dp[v][fromT][0][0] = c[v];
                dp[v][fromT][1][0] = d[v];
                if ( !inQ[v] ) inQ[v] = true, Q.push(v);
            }
        }
    }
}
int Run(int S, int T, int k, int n){
    Spfa_c(S, n, false);
    if ( dp[T][0][0][0] > k ) return -1;
    Spfa_w(S, n, false);
    Spfa_c(T, n, true);
    Spfa_w(T, n, true);
    int ans = oo;
    for (int i = 1; i <= n; ++i){
        int t1 = dp[i][0][0][0] + dp[i][1][0][0];
        int t2 = dp[i][0][0][0] + dp[i][1][0][1];
        int t3 = dp[i][0][0][1] + dp[i][1][0][0];
        int t4 = dp[i][0][0][1] + dp[i][1][0][1];
        if ( t1 <= k ) ans = min(ans, dp[i][0][1][0]+dp[i][1][1][0]);
        if ( t2 <= k ) ans = min(ans, dp[i][0][1][0]+dp[i][1][1][1]);
        if ( t3 <= k ) ans = min(ans, dp[i][0][1][1]+dp[i][1][1][0]);
        if ( t4 <= k ) ans = min(ans, dp[i][0][1][1]+dp[i][1][1][1]);
    }
    return ans;
}
int main()
{
    int n,m;
    while ( scanf("%d%d", &n, &m) != EOF ){
        Init(n);
        for (int i = 0; i < m; ++i){
            int a,b,c,d;
            scanf("%d%d%d%d", &a, &b, &c, &d);
            AddEdge(a, b, c, d); AddEdge(b, a, c, d);
        }
        int s, t, k;
        scanf("%d%d%d", &s, &t, &k);
        printf("%d\n", Run(s,t,k,n));
    }
    return 0;
}
View Code

 

[vijos Car的旅行路线]最短路

From:https://www.vijos.org/p/1119

Solution:裸的最短路, 需要通过矩形三点求第四点。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stack>
#include <functional>
using namespace std;
#define N 405
#define M 40005
#define oo 100000000000000
#define nil (-1)
struct {double w;int to,next;} nod[N*N];
double d[N];
bool inQ[N];
typedef pair<int,int> ipair;
pair<ipair, int> city[N][4];
int adj[N], now, S, T;
void Init(int n){
    now = 0; S = 0; T = n;
    for (int i = 0; i <= n; ++i) adj[i] = nil;
}
int NewNode(int u, double w){
    nod[now].to = u; nod[now].w = w; nod[now].next = nil;
    return now++;
}
void AddEdge(int u, int v, double w){
    int u1 = NewNode(v, w);
    nod[u1].next = adj[u]; adj[u] = u1;
}
double Spfa(int S, int T, int n){
    for (int i = 0; i <= n; ++i) d[i] = oo, inQ[i] = false;
    queue<int> Q;
    d[S] = 0; inQ[S] = true; Q.push(S);
    while ( !Q.empty() ){
        int u = Q.front(); Q.pop(); inQ[u] = false;
        for (int i = adj[u]; i != nil; i = nod[i].next){
            int v = nod[i].to;
            if ( d[v] > d[u] + nod[i].w && fabs(d[v]-d[u]-nod[i].w) > 1e-10 ){
                d[v] = d[u] + nod[i].w;
                if ( !inQ[v] ) inQ[v] = true, Q.push(v);
            }
        }
    }
    return d[T];
}
bool IsCos90(ipair const& P1, ipair const& P2){
    return !(P1.first*P2.first+P1.second*P2.second);
}
ipair FindPoint(ipair const& p1, ipair const& p2, ipair const& p3){
    if ( IsCos90(make_pair(p2.first-p1.first, p2.second-p1.second),
                 make_pair(p3.first-p1.first, p3.second-p1.second)) ){
        return make_pair(p2.first+p3.first-p1.first,p2.second+p3.second-p1.second);
    }

    if ( IsCos90(make_pair(p1.first-p2.first, p1.second-p2.second),
                 make_pair(p3.first-p2.first, p3.second-p2.second)) ){
        return make_pair(p1.first+p3.first-p2.first,p1.second+p3.second-p2.second);
    }
    return make_pair(p1.first+p2.first-p3.first,p1.second+p2.second-p3.second);
}
int main()
{
    int s,t,A,B;
    while ( scanf("%d%d%d%d", &s, &t, &A, &B) != EOF ){
        Init(4*s+1);
        for (int i = 0; i < s; ++i){
            int x1,y1,x2,y2,x3,y3,tt;
            scanf("%d%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &x3, &y3, &tt);
            city[i+1][0] = make_pair(make_pair(x1,y1), 4*i+1);
            city[i+1][1] = make_pair(make_pair(x2,y2), 4*i+2);
            city[i+1][2] = make_pair(make_pair(x3,y3), 4*i+3);
            city[i+1][3] = make_pair(FindPoint(ipair(x1,y1), ipair(x2,y2), ipair(x3,y3)), 4*i+4);
            for (int k1 = 0; k1 < 4; ++k1)
            for (int k2 = 0; k2 < 4; ++k2){
                if ( k1 == k2 ) continue;
                int x = city[i+1][k1].first.first-city[i+1][k2].first.first;
                int y = city[i+1][k1].first.second-city[i+1][k2].first.second;
                double dd = sqrt(x*x+y*y);
                AddEdge(city[i+1][k1].second, city[i+1][k2].second, dd*tt);
            }
        }
        for (int i = 1; i <= s; ++i)
        for (int j = 1; j <= s; ++j){
            if ( i == j ) continue;
            for (int k1 = 0; k1 < 4; ++k1)
            for (int k2 = 0; k2 < 4; ++k2){
                int x = city[i][k1].first.first-city[j][k2].first.first;
                int y = city[i][k1].first.second-city[j][k2].first.second;
                double dd = sqrt(x*x+y*y);
                AddEdge(city[i][k1].second, city[j][k2].second, dd*t);
            }
        }
        for (int i = 0; i < 4; ++i){
            AddEdge(S, city[A][i].second, 0);
        }
        for (int i = 0; i < 4; ++i){
            AddEdge(city[B][i].second, T, 0);
        }
        printf("%.2lf\n", Spfa(S, T, 4*s+1));
    }
    return 0;
}
View Code

 

[vijos 集合位置]最短路

From:https://www.vijos.org/p/1155

Solution:妈蛋, 就因为写了while(scanf("")){...}一直wa, 去掉就过了。 这题不能用d[n][2]表示最短和次短的方式做,因为是无向图,比较难处理。直接删边做即可。找到最短路径, 每次删除路径上的边(记得还原)后求最短路。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <stack>
#include <functional>
using namespace std;
#define N 205
#define M 40005
#define oo 99999999
#define nil (-1)
typedef pair<int,int> ipair;
int fa[N];
double d[N], w[N][N];
bool inQ[N];
ipair pt[N], path[M];
void Init(int n){
    for (int i = 0; i <= n; ++i)
    for (int j = 0; j <= n; ++j) w[i][j] = oo;
}
double Spfa(int s, int t, int n){
    for (int i = 0; i <= n; ++i){
        d[i] = oo; inQ[i] = false;
        fa[i] = nil;
    }
    queue<int> Q;
    d[s] = 0; Q.push(s); inQ[s] = true;
    while ( !Q.empty() ){
        int u = Q.front(); Q.pop(); inQ[u] = false;
        for (int v = 1; v <= n; ++v){
            if ( w[u][v] != oo && d[v] > d[u] + w[u][v] ){
                fa[v] = u;
                d[v] = d[u] + w[u][v];
                if ( !inQ[v] ) inQ[v] = true, Q.push(v);
            }
        }
    }
    return d[t];
}
void Run(int n){
    Spfa(1,n,n);
    int cnt = 0;
    for (int i = n; fa[i] != nil; i = fa[i]){
        path[cnt].first = fa[i];
        path[cnt++].second = i;
    }
    double ans = oo;
    for (int i = 0; i < cnt; ++i){
        int u = path[i].first, v = path[i].second;
        w[u][v] = w[v][u] = oo;
        Spfa(1,n,n);
        if ( d[n] < ans ) ans = d[n];
        int x = pt[u].first-pt[v].first;
        int y = pt[u].second-pt[v].second;
        double dd = sqrt(x*x+y*y);
        w[u][v] = w[v][u] = dd;
    }
    if ( ans == oo ) printf("-1\n");
    else printf("%.2lf\n", ans);
}
int main()
{
    int n,m;
    scanf("%d%d", &n, &m);
    Init(n);
    for (int i = 1; i <= n; ++i){
        int x,y;
        scanf("%d%d", &x, &y);
        pt[i] = make_pair(x,y);
    }
    for (int i = 1; i <= m; ++i){
        int a,b;
        scanf("%d%d", &a, &b);
        int x = pt[a].first-pt[b].first;
        int y = pt[a].second-pt[b].second;
        double dd = sqrt(x*x+y*y);
        w[a][b] = w[b][a] = dd;
    }
    Run(n);

    return 0;
}
View Code

 

[vijos 遭遇战]最短路, 简化的最小费用流

From:https://www.vijos.org/p/1404

Solution:依然是约束方程+差分。对于时刻Pi, 满足条件a1*X1+a2*X2+..+an*Xn <= 1, 这里ai={0,1}。最开始一直是按 = 1的方式做, 死活出错, 唉。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <map>
#include <functional>
using namespace std;
#define N 90002
#define M 10005
#define oo 0xefffffff
#define nil (-1)
typedef pair<unsigned int,int> ipair;
typedef pair<pair<int,int>,int> iipair;
struct Greater: public binary_function<ipair,ipair,bool>{
    bool operator()(const ipair& L, const ipair& R) const{
        return L.first > R.first;
    }
};
typedef priority_queue<ipair, vector<ipair>, Greater> pri_que;
struct {unsigned int w; int to,next;} nod[N+M];
int now;
unsigned int adj[N], d[N];
void Init(int n){
    now = 0;
    for (int i = 0; i <= n; ++i) adj[i] = nil;
}
int NewNode(int u, unsigned int w){
    nod[now].to = u; nod[now].w = w; nod[now].next = nil;
    return now++;
}
void AddEdge(int u, int v, unsigned int w){
    int u1 = NewNode(v, w);
    nod[u1].next = adj[u]; adj[u] = u1;
}
void Dijkstra(int s, int t, int n){
    for (int i = 0; i <= n; ++i) d[i] = oo;
    pri_que Q;
    d[s] = 0; Q.push(make_pair(0, s));
    while ( !Q.empty() ){
        int u = Q.top().second; Q.pop();
        for (int i = adj[u]; i != nil; i = nod[i].next){
            int v = nod[i].to;
            if ( d[v] > d[u] + nod[i].w ){
                d[v] = d[u] + nod[i].w;
                Q.push(make_pair(d[v], v));
            }
        }
    }
}
int main()
{
    int n, s, e;
    scanf("%d%d%d", &n, &s, &e);
    Init(e+1);
    for (int i = 0; i < n; ++i){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        if ( b < s ) continue;
        if ( a > e ) continue;
        if ( a < s ) a = s;
        if ( b > e ) b = e;
        AddEdge(a,b+1,c);
    }
    for (int i = s+1; i <= e+1; ++i) AddEdge(i,i-1,0);
    Dijkstra(s, e+1, e+1);
    if ( d[e+1] == oo ) printf("-1\n");
    else printf("%u\n", d[e+1]);
    return 0;
}
View Code

 

[vijos 社交网络]最短路 floyd 路径统计

From:https://www.vijos.org/p/1591

Solution:dp[i,j]表示从i到j的最短路径数。dp[i,j]=dp[i,k]*dp[k,j], d[i,j]>d[i,k]+d[k,j]; dp[i,j]+=dp[i,k]*dp[k,j], d[i,j]==d[i,k]+d[k,j]。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <map>
#include <functional>
using namespace std;
#define N 102
#define M 8005
#define oo 0x0fffffff
#define nil (-1)
int w[N][N], d[N][N];
long long dp[N][N];
void Init(int n){
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j) w[i][j] = oo;
}
void Floyd(int n){
    for (int i = 1; i <= n; ++i){
        for (int j = 1; j <= n; ++j) d[i][j] = w[i][j], dp[i][j] = (w[i][j]!=oo);
        d[i][i] = 0;
    }
    for (int k = 1; k <= n; ++k)
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j)
        if ( d[i][j] > d[i][k]+d[k][j] ){
            d[i][j] = d[i][k]+d[k][j];
            dp[i][j] = dp[i][k]*dp[k][j];
        }else if ( d[i][j] == d[i][k]+d[k][j] ){
            dp[i][j] += dp[i][k]*dp[k][j];
        }
}
void Run(int n){
    Floyd(n);
    for (int i = 1; i <= n; ++i){
        double ans = 0;
        for (int s = 1; s <= n; ++s)
        for (int t = 1; t <= n; ++t){
            if ( s == t || i == s || i == t || !dp[s][t] ) continue;
            if ( d[i][s] + d[i][t] != d[s][t] ) continue;
            ans += dp[i][s]*dp[i][t]/(double)dp[s][t];
        }
        printf("%.3f\n", ans);
    }
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    Init(n);
    for (int i = 0; i < m; ++i){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        w[a][b] = w[b][a] = c;
    }
    Run(n);
    return 0;
}
View Code
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <map>
#include <functional>
using namespace std;
#define N 102
#define M 8005
#define oo 0x0fffffff
#define nil (-1)
typedef pair<unsigned int,int> ipair;
struct Greater: public binary_function<ipair,ipair,bool>{
    bool operator()(const ipair& L, const ipair& R) const{
        return L.first > R.first;
    }
};
typedef priority_queue<ipair,vector<ipair>,Greater> pri_que;
struct {int w; int to,next;} nod[M];
int adj[N], d[N][N], now;
bool outQ[N]; // 是否出过队列
long long dp[N][N];
void Init(int n){
    now = 0;
    for (int i = 0; i <= n; ++i) adj[i] = nil;
}
int NewNode(int u, int w){
    nod[now].to = u; nod[now].w = w; nod[now].next = nil;
    return now++;
}
void AddEdge(int u, int v, int w){
    int u1 = NewNode(v, w);
    nod[u1].next = adj[u]; adj[u] = u1;
}
void Dijkstra(int S, int n){
    for (int i = 0; i <= n; ++i) d[S][i] = oo, outQ[i] = false;
    pri_que Q;
    d[S][S] = 0; Q.push(make_pair(0,S)); dp[S][S] = 1;
    while ( !Q.empty() ){ // Dijkstra是永久定标, 出过一次就不需要处理了, 这里用stl会进多次
        int u = Q.top().second; Q.pop();
        if ( outQ[u] ) continue;
        outQ[u] = true;
        for (int i = adj[u]; i != nil; i = nod[i].next){
            int v = nod[i].to;
            if ( d[S][v] > d[S][u] + nod[i].w ){
                dp[S][v] = dp[S][u];
                d[S][v] = d[S][u] + nod[i].w;
                Q.push(make_pair(d[S][v], v));
            } else if ( d[S][v] == d[S][u] + nod[i].w ) dp[S][v] += dp[S][u];
        }
    }
}
void Run(int n){
    for (int i = 1; i <= n; ++i) Dijkstra(i, n);
    for (int i = 1; i <= n; ++i){
        double ans = 0;
        for (int s = 1; s <= n; ++s)
        for (int t = 1; t <= n; ++t){
            if (  i == s || i == t || !dp[s][t] ) continue;
            if ( d[i][s] + d[i][t] != d[s][t] ) continue;
            ans += dp[i][s]*dp[i][t]/(double)dp[s][t];
        }
        printf("%.3f\n", ans);
    }
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    Init(n);
    for (int i = 0; i < m; ++i){
        int a,b,c;
        scanf("%d%d%d", &a, &b, &c);
        AddEdge(a,b,c); AddEdge(b,a,c);
    }
    Run(n);

    return 0;
}
View Code

[vijos 小D的旅行]最短路 floyd 状态记录

From:https://www.vijos.org/p/1746

Solution: d[i,j,0]表示不用加油的最小费用, 直接floyd; d[i,j,1]表示用加油的最小费用, d[i,j,1]=min(d[i,j,1],d[i,k,0]+d[k,j,0]+c[k])。

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <map>
#include <functional>
using namespace std;
#define N 302
#define M 25005
#define oo 0x0fffffff
#define nil (-1)
int w[N][N], d[N][N][2], c[N];
void Init(int n){
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j) w[i][j] = oo;
}
void Floyd(int n){
    for (int i = 1; i <= n; ++i){
        for (int j = 1; j <= n; ++j){
            if ( w[i][j] == oo ) d[i][j][0] = d[i][j][1] = oo;
            else d[i][j][0] = w[i][j], d[i][j][1] = oo;
        }
        d[i][i][0] = 0;
    }

    for (int k = 1; k <= n; ++k)
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j){
        d[i][j][0] = min(d[i][j][0], d[i][k][0] + d[k][j][0]);
    }
    for (int k = 1; k <= n; ++k)
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j){
        d[i][j][1] = min(d[i][j][1], d[i][k][0] + d[k][j][0]+c[k]);
    }
}
int main()
{
    int n,m;
    scanf("%d%d", &n, &m);
    Init(n);
    for (int i = 1; i <= n; ++i) scanf("%d", c+i);
    for (int i = 1; i <= m; ++i){
        int a,b,dd;
        scanf("%d%d%d", &a, &b, &dd);
        w[a][b] = w[b][a] = min(w[a][b], dd);
    }
    Floyd(n);
    int q;
    scanf("%d", &q);
    while ( q-- ){
        int u,v;
        scanf("%d%d", &u, &v);
        if ( d[u][v][1] != oo )
            printf("%d\n", d[u][v][1]);
        else
            printf("-1\n");
    }
    return 0;
}
View Code

 

posted on 2013-12-28 15:38  leezyli  阅读(251)  评论(0编辑  收藏  举报

导航