1. 程式人生 > >2017多校第9場 HDU 6166 Senior Pan 堆優化Dij

2017多校第9場 HDU 6166 Senior Pan 堆優化Dij

step log push 隨機 我們 spa lld 做的 http

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6166

題意:給你一個有向圖,然後給你k個點,求其中一個點到另一個點的距離的最小值。

解法:枚舉二進制位按照標號當前位為1 和當前位為0分為兩個集合,每次求解兩個集合之間的最短路即可覆蓋到所有的點對。時間復雜度20*dijstla時間,這樣做的正確性在哪?顯然我們需要的答案至少有一個二進制位不同,那麽這樣求解肯定可以找到正確答案,事實上還可以隨機分組emmmm。。。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100010;
const LL inf = 0x3f3f3f3f3f3f3f3f;
struct edge{
    int to,val,next;
}E[maxn];
int head[maxn],edgecnt,a[maxn];
bool vis[maxn];
LL dis[maxn];
void initedge(){
    edgecnt=0;
    memset(head,-1,sizeof(head));
}
void add(int u, int v, int w){
    E[edgecnt].to=v,E[edgecnt].val=w,E[edgecnt].next=head[u],head[u]=edgecnt++;
}
struct node{
    int x;
    LL step;
    node(int x, LL step):x(x),step(step){}
    bool operator < (const node &rhs) const{
        return step>rhs.step;
    }
};
priority_queue<node>q;
LL Dijstra(){
    while(!q.empty()){
        node now=q.top(); q.pop();
        if(vis[now.x]) return now.step;
        int u=now.x;
        for(int i=head[u]; ~i; i=E[i].next){
            int to = E[i].to;
            if(dis[to]>dis[u]+E[i].val){
                dis[to]=dis[u]+E[i].val;
                q.push(node(to,dis[to]));
            }
        }
    }
    return inf;
}
void init(){
    memset(vis, 0, sizeof(vis));
    for(int i=0; i<maxn; i++) dis[i]=inf;
    while(!q.empty()) q.pop();
}
LL work(int k)
{
    LL ans = inf;
    for(int i=0; i<20; i++){
        init();
        for(int j=1; j<=k; j++){
            if(a[j]&(1<<i)){
                q.push(node(a[j],0)),dis[a[j]]=0;
            }
            else{
                vis[a[j]]=1;
            }
        }
        ans = min(ans, Dijstra());
        init();
        for(int j=1; j<=k; j++){
            if(a[j]&(1<<i)){
                vis[a[j]]=1;
            }
            else{
                q.push(node(a[j],0)),dis[a[j]]=0;
            }
        }
        ans = min(ans, Dijstra());
    }
    return ans;
}
int T,n,m,k,ks;
int main()
{
    ks = 0;
    scanf("%d", &T);
    while(T--)
    {
        initedge();
        scanf("%d %d",&n,&m);
        for(int i=1; i<=m; i++){
            int u, v, w;
            scanf("%d %d %d", &u,&v,&w);
            add(u, v, w);
        }
        scanf("%d", &k);
        for(int i=1; i<=k; i++) scanf("%d", &a[i]);
        LL ans = work(k);
        printf("Case #%d: %lld\n", ++ks, ans);
    }
    return 0;
}

2017多校第9場 HDU 6166 Senior Pan 堆優化Dij