P1967のトラック輸送[スパニングツリー+ LCA]

タイトル説明

国有のnに1から番号都市、N、都市間にあるM双方向道路。すべての道は重量制限と呼ばれる車の重量制限があります。Q *トラックは商品の輸送にありますが、ドライバは、複数の商品を輸送するまで、車両の重量制限を超えることなく、すべての車を知ってほしいです。

解決

私は、こんにゃくは午前デバッグ一方向双方向の側縁に一緒に入れて見ます

唯一の問い合わせがある場合はもちろん、私たち貪欲にもエッジが起動および終了接続できるようになるまで。我々はまだ貪欲、最小スパニングツリーと同じで、「最大のスパニング・ツリー」に従事するために行うことができますように多くが、尋ねるがある場合は、(私が持っている場合、私は知らない)出てきましたそして、あなたも木を横断することができますそして、私たちは木々にいじり、ちょうどライン上のツリー・アルゴリズムで任意の2点間の最小重量パスを計算します。

ここで私は木が、その後分が最終的な答えである2つの値をとり、それぞれ、統計が2 LCAへの最低重量を指し、LCAを求めて倍増使用しました。

参照コード

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define N 500010
#define INF 0x7fffffff
#define IN freopen("data.in","r",stdin);
using namespace std;
inline int read()
{
    int f=1,x=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct node{
    int from,to,edge;
}a[N];
struct rec{
    int next,ver,edge;
}g[N];
int head[N],tot;
int fa[N],f[30][N],w[30][N],d[N],n,m;//f[i][x]表示x节点的2^i辈父亲,w[i][x]表示x节点到其2^i辈父亲的最小权值,d[x]表示节点x的深度 
queue<int> q;
inline void add(int x,int y,int val)
{
    g[++tot].ver=y,g[tot].edge=val;
    g[tot].next=head[x],head[x]=tot;
}
inline int get(int x)
{
    return fa[x]==x?x:fa[x]=get(fa[x]);
}
inline void merge(int x,int y)
{
    x=get(x),y=get(y);
    if(x!=y) fa[x]=y;
}
inline void init(int x)//BFS预处理f[][],w[][] 
{
    q.push(x);d[x]=1;
    while(q.size()){
        int index=q.front();q.pop();
        for(int i=head[index];i;i=g[i].next){
            int y=g[i].ver,z=g[i].edge;
            if(d[y]) continue;
            f[0][y]=index;w[0][y]=z;
            d[y]=d[index]+1;
            for(int j=1;j<25;++j){
                f[j][y]=f[j-1][f[j-1][y]];
                w[j][y]=min(w[j-1][y],w[j-1][f[j-1][y]]);//仿照ST表求法预处理w数组 
            }
        q.push(y);
        }
    }
}
inline int calc(int x,int y)//倍增求LCA 
{
    int ans=INF;
    if(d[x]>d[y]) swap(x,y);
    for(int i=24;i>=0;--i)
        if(d[f[i][y]]>=d[x]) ans=min(ans,w[i][y]),y=f[i][y];
    if(x==y) return ans;
    for(int i=24;i>=0;--i){
        if(f[i][y]==f[i][x]) continue;
        ans=min(ans,min(w[i][y],w[i][x])),x=f[i][x],y=f[i][y];
    }
    if(x==y) return ans;
    ans=min(ans,min(w[0][x],w[0][y]));
    return ans;
}
bool cmp(node a,node b){return a.edge>b.edge;}
int main()
{
    //IN
    int q;
    n=read(),m=read();
    for(int i=1;i<=m;++i)
        a[i].from=read(),a[i].to=read(),a[i].edge=read();
    sort(a+1,a+m+1,cmp);//最大生成树,并查集实现 
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=m;++i){
        int x=get(a[i].from),y=get(a[i].to);
        if(x==y) continue;
        merge(x,y),add(a[i].from,a[i].to,a[i].edge),add(a[i].to,a[i].from,a[i].edge);
    }
    memset(w,0x3f,sizeof(w));
    for(int i=1;i<=n;++i)
        if(!d[i]) init(i);//可能出现森林 
    q=read();
    for(int i=1;i<=q;++i){
        int u,v;
        u=read(),v=read();
        int x=get(u),y=get(v);
        if(x!=y){
            printf("-1\n");continue;//如果两个点不在一棵树上,无解 
        }
        printf("%d\n",calc(u,v));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/DarkValkyrie/p/11308625.html