1. 程式人生 > >貨車運輸(最大生成樹+LCA)

貨車運輸(最大生成樹+LCA)

整數 fine std 一個 ext getchar() 最小路徑 ont getch

題目描述

A 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。

輸入輸出格式

輸入格式:

輸入文件名為 truck.in。

輸入文件第一行有兩個用一個空格隔開的整數 n,m,表示 A 國有 n 座城市和 m 條道

路。 接下來 m 行每行 3 個整數 x、 y、 z,每兩個整數之間用一個空格隔開,表示從 x 號城市到 y 號城市有一條限重為 z 的道路。註意: x 不等於 y,兩座城市之間可能有多條道路 。

接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。

接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,註意: x 不等於 y 。

輸出格式:

輸出文件名為 truck.out。

輸出共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨

車不能到達目的地,輸出-1。

輸入輸出樣例

輸入樣例#1:
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
輸出樣例#1:
3
-1
3

說明

對於 30%的數據,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000;

對於 60%的數據,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000;

對於 100%的數據,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。

題中要求的是圖中任意兩點間的路徑的最小值最大是多少

貨車要盡可能的運多的貨物,就需要盡可能走權值大的路

所以路徑一定在圖中的最大生成樹上

得到最大生成樹後,很容易發現兩點間的路徑一定經過它們的最近公共祖先,

則可以利用倍增的思想,設p[i][j]表示i節點第2^j個祖先,minx[i][j]表示從i到2^j個祖先的路徑最小值

轉移方程:p[i][j]=p[p[i][j-1]][j-1]

     minx[i][j]=min(minx[i][j-1],minx[p[i][j-1][j-1])

利用兩個數組去求lca和最小路徑即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#define MAXN 10050
#define MAXE 50050
#define INF 2147483647
using namespace std;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
int father[MAXN];
int finds(int x)
{
    if(father[x]==x) return x;
    return father[x]=finds(father[x]);
}
struct Line
{
    int u,v,w;
    friend bool operator<(Line a,Line b)
    {
        return a.w>b.w;
    }
} l[MAXE];
struct Edge
{
    int u,v,w;
    int next;
} e[MAXE];
int head[MAXN],cnt=0;
void add(int u,int v,int w)
{
    cnt++;
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
int n,m,q,deep[MAXN],p[MAXN][20],minx[MAXN][20],deps;
void kruskal()
{
    for(int i=1; i<=n; i++)father[i]=i;
    sort(l+1,l+m+1);
    for(int i=1; i<=m; i++)
    {
        int u=finds(l[i].u);
        int v=finds(l[i].v);
        if(u!=v)
        {
            father[v]=u;
            add(l[i].u,l[i].v,l[i].w);
            add(l[i].v,l[i].u,l[i].w);
        }
    }
}
void dfs(int u)
{
    for(int i=head[u]; i!=0; i=e[i].next)
        if(!deep[e[i].v])
        {
            deep[e[i].v]=deep[u]+1;
            p[e[i].v][0]=u;
            minx[e[i].v][0]=e[i].w;
            dfs(e[i].v);
        }
}
inline int lca(int x, int y)
{
    int ans=INF;
    if(deep[x]>deep[y]) swap(x, y);
    for(int i=15; i>=0; i--)
        if(deep[p[y][i]]>=deep[x])
        {
            ans=min(ans,minx[y][i]);
            y=p[y][i];
        }
    if(x==y) return ans;
    for(int i=15; i>=0; i--)
        if(p[x][i]!=p[y][i])
        {
            ans = min(ans, min(minx[x][i], minx[y][i]));
            x=p[x][i];
            y=p[y][i];
        }
    return min(ans, min(minx[x][0], minx[y][0]));
}
int main()
{
    n=read(),m=read();
    for(int i=1; i<=m; i++)
        l[i].u=read(),l[i].v=read(),l[i].w=read();
    kruskal();
    deep[1]=1;
    dfs(1);
    for(int j=1; j<=15; j++)
        for(int i=1; i<=n; i++)
        {
            p[i][j]=p[p[i][j-1]][j-1];
            minx[i][j]=min(minx[i][j-1],minx[p[i][j-1]][j-1]);
        }
    q=read();
    for(int i=1; i<=q; i++)
    {
        int u=read(),v=read();
        if(finds(u)!=finds(v))
        {
            printf("-1\n");
            continue;
        }
        printf("%d\n",lca(u,v));
    }
}

貨車運輸(最大生成樹+LCA)