zoukankan      html  css  js  c++  java
  • HDU 6166 Senior Pan(k点中最小两点间距离)题解

    题意:n个点,m条有向边,指定k个点,问你其中最近的两点距离为多少

    思路:这题的思路很巧妙,如果我们直接枚举两点做最短路那就要做C(k,2)次。但是我们换个思路,我们把k个点按照二进制每一位的0和1分类logn次,然后做集合最短距离。因为任意两个不等的数,总有一位不一样,所以每个点都有机会和其他点在不同集合。那么这样就花了logn次枚举了所有情况。集合最短距离可以指定一个超级源点和超级汇点,然后做两点最短路。

    代码:

    #include<cmath>
    #include<set>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include <iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 100000 + 10;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1000000007;
    struct Edge{
        int to, w, next;
    }edge[maxn * 2];
    struct node{
        int v, w;
        node(int _v = 0, int _w = 0): v(_v), w(_w){}
        bool operator < (const node r) const{
            return w > r.w;
        }
    };
    int head[maxn], tot;
    void addEdge(int u, int v, int w){
        edge[tot].w = w;
        edge[tot].to = v;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    int n, m, k;
    int dis[maxn], q[maxn];
    bool vis[maxn];
    int dij(int s, int e){
        memset(vis, false, sizeof(vis));
        memset(dis, INF, sizeof(dis));
        priority_queue<node> Q;
        while(!Q.empty()) Q.pop();
        dis[s] = 0;
        Q.push(node(s, 0));
        node tmp;
        while(!Q.empty()){
            tmp = Q.top();
            Q.pop();
            int u = tmp.v;
            if(vis[u]) continue;
            vis[u] = true;
            for(int i = head[u]; i != -1; i = edge[i].next){
                int v = edge[i].to;
                if(!vis[v] && dis[v] > dis[u] + edge[i].w){
                    dis[v] = dis[u] + edge[i].w;
                    Q.push(node(v, dis[v]));
                }
            }
        }
        return dis[e];
    }
    void init(){
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    int a[maxn], b[maxn], w[maxn];
    int main(){
        int T, ca = 1;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= m; i++){
                scanf("%d%d%d", &a[i], &b[i], &w[i]);
            }
            scanf("%d", &k);
            for(int i = 1; i <= k; i++){
                scanf("%d", &q[i]);
            }
            int ans = INF, p = 0;
            while(n >> p){
                init();
                for(int i = 1; i <= m; i++)
                    addEdge(a[i], b[i], w[i]);
                for(int i = 1; i <= k; i++){
                    if((q[i] >> p) & 1){
                        addEdge(0, q[i], 0);
                    }
                    else{
                        addEdge(q[i], n + 1, 0);
                    }
                }
                ans = min(ans, dij(0, n + 1));
                init();
                for(int i = 1; i <= m; i++)
                    addEdge(a[i], b[i], w[i]);
                for(int i = 1; i <= k; i++){
                    if((q[i] >> p) & 1){
                        addEdge(q[i], 0, 0);
                    }
                    else{
                        addEdge(n + 1, q[i], 0);
                    }
                }
                ans = min(ans, dij(n + 1, 0));
                p++;
            }
            printf("Case #%d: %d
    ", ca++, ans);
        }
        return 0;
    }
  • 相关阅读:
    《Mathematical Olympiad——组合数学》——染色问题
    《啊哈算法》——栈、队列、链表
    《Mathematical Olympiad——组合数学》——抽屉原理
    2749: [HAOI2012]外星人
    bzoj4241: 历史研究
    bzoj3210: 花神的浇花集会
    bzoj4998: 星球联盟
    bzoj2728: [HNOI2012]与非
    bzoj2669: [cqoi2012]局部极小值
    bzoj5441: [Ceoi2018]Cloud computing
  • 原文地址:https://www.cnblogs.com/KirinSB/p/10679711.html
Copyright © 2011-2022 走看看