NOIP2014トラック輸送

タイトルを実行する前に長い時間が、書かれた記述する価値があります。

常に尋ねる(Uは、V \)\二点間の全ての経路において、最小エッジウェイト最大です。

(便宜上、以下の書き込み時間の複雑\(N- \)、\ (M \)、\ (Q \)すべての書かれた\(N- \) )。

アルゴリズム1

図の下降側の順に右側2点まで加えた\(U \)\(V \)通信が可能であり、最終的にその縁の右側に追加され、\((UをV)\)このクエリへの答え。接続性を維持するために、ばらばらのセット。

私たちは、オフライン処理を検討してください。

具体的には、我々はポイントの小さいのそれぞれに接続され、このエッジの2つの通信ブロックを横断する一の各側面を加え\(U \) 参照\(U \)に関する情報の要求を\((u、v)は\ ) ここで\(V \)他の通信ブロックにおいて、次に答えがちょうどこの辺の重みを追加依頼することです。

我々はを通じて発見し、それがわずかに達成するための一般的な互いに素なセットを修正することができるが、動作のセットをサポートするためにチェックが、組み合わさヒューリスティックたvector簡単にこの機能を達成することができます。特定のコードで参照してください。

ヒューリスティックを組み合わせているので、全時間の複雑さは、\(O(N \ \)N-ログ)、空間的複雑である\(O(N \ N-ログ)\) によって。

#include<cstdio>
#include<algorithm>
#include<vector>
const int N=10003,Q=30003,M=50003;
int n,m,q,ans[Q],p[N],siz[N];
struct edge{int u,v,c;}g[M];
bool Cmp(const edge&a,const edge&b){return a.c>b.c;}
struct query{int v,p;};std::vector<query>h[N];
std::vector<int>t[N];
int main(){
    int u,v,x,y,tmp;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&g[i].u,&g[i].v,&g[i].c);
    std::sort(g+1,g+1+m,Cmp);
    scanf("%d",&q);
    for(int j=1;j<=q;j++){
      scanf("%d%d",&u,&v);
      h[u].push_back((query){v,j}),h[v].push_back((query){u,j});
      ans[j]=-1;
    }
    for(u=1;u<=n;u++)p[u]=u,t[u].push_back(u),siz[u]=1;
    for(int i=1;i<=m;i++)if((u=p[g[i].u])!=(v=p[g[i].v])){
      if(siz[u]>siz[v])tmp=u,u=v,v=tmp;
      for(int j=0;j<t[u].size();j++){
        x=t[u][j];
        for(int j=0;j<h[x].size();j++)
          if(p[h[x][j].v]==v)ans[h[x][j].p]=g[i].c;
      }
      for(int j=0;j<t[u].size();j++)
        t[v].push_back(t[u][j]),p[t[u][j]]=v;
      siz[v]+=siz[u];
    }
    for(int j=1;j<=q;j++)printf("%d\n",ans[j]);
    return 0;
}

アルゴリズム2

実際には、我々は、このプロセスとすることを見つけるKruskal最大のスパニングツリーのアルゴリズムは同じです。

そう\(Uは\)、\ (V \)を満たすスパニングツリー最大で一定の最小値との間の経路の右側-実際には、図の通信ので保証されていない、これは実際には森林、最大の生成です。

第1の最大スパニング森に図を構築し、次に技術鎖またはパスエッジの高速最小のツリーの分割値を乗じます。このアプローチは、時間複雑です\(O(N \ N-ログ)\) 渡すことができます。

#include<cstdio>
#include<algorithm>
using namespace std;
int read(){
    int a=0;char c=getchar();
    while(c<48||c>57)c=getchar();while(c>47&&c<58)a=a*10+c-48,c=getchar();
    return a;
}
struct edge{int u,v,c;}e[50000];
bool cmp(edge a,edge b){return a.c>b.c;}
struct node{int v,c,nxt;}mst[20000];
int n,m,p[10000],head[10000],k,d[10000],f[10000][14],mn[10000][14];
int Insert(int u,int v,int c){mst[++k]=(node){v,c,head[u]};head[u]=k;}
int Find(int a){return p[a]==a?a:p[a]=Find(p[a]);}
int Mst(){
    sort(e,e+m,cmp);
    for(int i=0;i<m;i++)if(Find(e[i].u)!=Find(e[i].v)){
      p[Find(e[i].u)]=Find(e[i].v);
      Insert(e[i].u,e[i].v,e[i].c);Insert(e[i].v,e[i].u,e[i].c);
    }
}
int dfs(int u){
    int v;
    for(int i=head[u];i;i=mst[i].nxt)if(!d[v=mst[i].v])
      d[v]=d[u]+1,f[v][0]=u,mn[v][0]=mst[i].c,dfs(v);
}
int Pathmin(int u,int v){
    int s=1e9;
    if(d[u]<d[v])u^=v,v^=u,u^=v;
    for(int i=d[u]-d[v],k=0;i;i>>=1,k++)
      if(i&1)s=min(s,mn[u][k]),u=f[u][k];
    if(u==v)return s;
    for(int i=13;~i;i--)
      if(f[u][i]!=f[v][i])
        s=min(s,min(mn[u][i],mn[v][i])),u=f[u][i],v=f[v][i];
    return min(s,min(mn[u][0],mn[v][0]));
}
int main(){
    int u,v;
    n=read();m=read();
    for(int i=1;i<=n;i++)p[i]=i;
    for(int i=0;i<m;i++)
      e[i].u=read(),e[i].v=read(),e[i].c=read();
    Mst();
    for(int i=1;i<=n;i++)if(!d[i])d[i]=1,dfs(i);
    for(int j=1;j<=13;j++)
      for(int i=1;i<=n;i++)
        f[i][j]=f[f[i][j-1]][j-1],mn[i][j]=min(mn[i][j-1],mn[f[i][j-1]][j-1]);
    m=read();
    while(m--){
      u=read();v=read();
      if(Find(u)!=Find(v))puts("-1");
      else printf("%d\n",Pathmin(u,v));
    }return 0;
}

おすすめ

転載: www.cnblogs.com/Camp-Nou/p/11815712.html
おすすめ