題解:[GXOI/GZOI2019]旅行者

調這個題調了兩個月,被自己蠢哭

題意:

   給一個有向圖,一組關鍵點,求關鍵點之間的最短的距離

Solution:

  這個題目有兩種做法,分別是 $nlogn$ 和 $nlog^2n$ 的

  首先說 $nlogn$ 的官方做法,我們考慮多源迪傑斯特拉

正圖上從 k 個關鍵點出發跑 $dijkstra$ ,記某個點離最近的關鍵點距離爲 $dis[0][i]$

反圖上也從 k 個關鍵點出發跑 $dijkstra$ ,距離記爲 $dis[1][i]$

枚舉正圖中的邊 $u->v: w$, 用 $dis[0][u]+dis[1][v]+w$ 更新答案

  然後就是一種很好打的 $nlognlogk$ 的做法,我們考慮一種思想,二進制分組

對於每一個在集合中的元素,我們進行重新標號,然後對每一位進行$0/1$二進制分組,由於每個元素的編號不一樣,所以至少有一位的分組不同,然後一組連 $S$,一組連 $T$,這樣跑 $logk$ 組的從 $S$ 到 $T$ 的最短路,去 $min$,即可

#include <bits/stdc++.h>
using namespace std;

#define re register
#define ll long long
#define gc getchar()
inline int read()
{
 	re int x(0),f(1);re char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}

const int N=5e5+10,M=1e6+10;
ll INF=1e15+7;
int h[N],n,m,cnt,k,a[N],x[N],y[N],z[N],s,t;
struct node {int next,to,w;}e[M<<1]; 
ll dis[N],ans=INF;
void add(int u,int v,int w){e[++cnt]=(node){h[u],v,w},h[u]=cnt;}
#define QXX(u) for(int i=h[u],v;v=e[i].to,i;i=e[i].next) 

struct Node 
{
    int id;ll d;
    bool operator < (const Node a) const {return d>a.d;}
};
priority_queue<Node>q;

void dijkstra()
{
    while(!q.empty()) q.pop();
    for(int i=1;i<=t;++i)
        dis[i]=INF;
    dis[s]=0;
    Node a;
    int u,d;
    q.push((Node){s,0});
    while(!q.empty())
    {
        a=q.top(),q.pop();
        u=a.id,d=a.d;
        if(d!=dis[u]) continue;
        QXX(u)
            if(dis[u]+e[i].w<dis[v])
            {
                dis[v]=dis[u]+e[i].w;
                q.push((Node){v,dis[v]});
            }
    }
} 

void work()
{
    ans=INF;
    n=read(),m=read(),k=read();
    s=n+1,t=n+2;
    for(int i=1;i<=m;++i)
        x[i]=read(),y[i]=read(),z[i]=read();
    for(int i=1;i<=k;++i)
        a[i]=read();
    for(int q=0;(1<<q)<=k;++q)
    {
        memset(h,0,sizeof(h));
        cnt=0;
        for(int i=1;i<=k;++i)
        {
            if(i&(1<<q)) add(s,a[i],0);
            else add(a[i],t,0); 
        }
        for(int i=1;i<=m;++i)
            add(x[i],y[i],z[i]);
        dijkstra();
        ans=min(ans,dis[t]);
        memset(h,0,sizeof(h));
        cnt=0;
        for(int i=1;i<=k;++i)
        {
            if(i&(1<<q)) add(s,a[i],0);
            else add(a[i],t,0); 
        }
        for(int i=1;i<=m;++i)
            add(y[i],x[i],z[i]);
        dijkstra();
        ans=min(ans,dis[t]);
    }
    cout<<ans<<endl;
}

int main()
{
    int T=read();
    while(T--) work();
    return 0;
} 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章