zoukankan      html  css  js  c++  java
  • HDU 6166 Senior Pan(多校第九场 二进制分组最短路)

    题意:给出n个点和m条有向边(有向边!!!!我还以为是无向查了半天),然后给出K个点,问这k个点中最近的两点的距离

    思路:比赛时以为有询问,就直接丢了,然后这题感觉思路很棒,加入把所有点分成起点和终点两部分,然后加个S点和T点与他们

    的距离为0,然后跑最短路就可以了,但是这样有可能最近的两个点都在起点或者都在终点,那么就不一定是最短的,所以就有个二进制分组。

    考虑每个点的编号的二进制表示,那么对于任何两个点,他们至少有一位二进制不同,那么我们通过枚举二进制的位,当前位为1的作为起点集合,

    当前位为2的作为终点集合,通过这样分组,我们就可以确定至少有一次分组任意两点分别在起点和终点。

    复杂度O(20*nlogm)

    代码:

    /** @xigua */
    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <stack>
    #include <cstring>
    #include <queue>
    #include <set>
    #include <string>
    #include <map>
    #include <climits>
    #define PI acos(-1)
    using namespace std;
    typedef long long ll;
    typedef double db;
    const int maxn = 1e5 + 5;
    const int mod = 1e9 + 7;
    const int INF = 1e8 + 5;
    const ll inf = 1e15 + 5;
    const db eps = 1e-5;
    int cnt, head[maxn]; ll dis[maxn];
    struct Edge {
        int v, next; ll w; //记住这里改顺序下面push进队一定要改!
        bool operator < (const Edge &rhs) const {
            return w > rhs.w;
        }
    } e[maxn<<2];
    
    void add(int u, int v, int co) {
        e[cnt].v = v;
        e[cnt].w = co;
        e[cnt].next = head[u];
        head[u] = cnt++;
    }
    
    void init() {
        cnt = 0;
        memset(head, -1, sizeof(head));
    }
    
    void dij(int s, int len) {
        priority_queue<Edge> pq;
        for (int i = 1; i <= len; i++)
            dis[i] = inf;
        bool vis[maxn] = {0};
        dis[s] = 0;
        pq.push((Edge){s, 0, 0});
        while (!pq.empty()) {
            Edge tmp = pq.top(); pq.pop();
            if (vis[tmp.v]) continue;
            vis[tmp.v] = 1;
            for (int i = head[tmp.v]; ~i; i = e[i].next) {
                Edge u = e[i];
                if (dis[u.v] > dis[tmp.v] + u.w) {
                    dis[u.v] = dis[tmp.v] + u.w;
                    pq.push((Edge){u.v, 0, dis[u.v]});
                }
            }
        }
    }
    int a[maxn];
    int u[maxn], v[maxn], w[maxn];
    
    void solve() {
        int n, m; cin >> n >> m;
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", u + i, v + i, w + i);
        }
        int k; cin >> k;
        for (int i = 1; i <= k; i++) {
            scanf("%d", a + i);
        }
        ll ans = inf;
        for (int i = 0; i < 20; i++) {
            init();
            for (int j = 1; j <= m; j++) {
                add(u[j], v[j], w[j]);
               // add(v[j], u[j], w[j]);
            }
            for (int j = 1; j <= k; j++) {
                if ((1<<i) & j) {
                    add(0, a[j], 0);
                }
                else {
                    add(a[j], n+1, 0);
                }
            }
            dij(0, n + 10);
            ans = min(ans, dis[n+1]);
            init();
            for (int j = 1; j <= m; j++) {
                add(u[j], v[j], w[j]);
               // add(v[j], u[j], w[j]);
            }
            for (int j = 1; j <= k; j++) {
                if (((1<<i) & j) == 0) {
                    add(0, a[j], 0);
                }
                else {
                    add(a[j], n+1, 0);
                }
            }
            dij(0, n + 10);
            ans = min(ans, dis[n+1]);
        }
        cout << ans << endl;
    }
    
    int main() {
        int t = 1, cas = 1;
       // freopen("in.txt", "r", stdin);
       // freopen("in.txt", "w", stdout);
       // init();
        scanf("%d", &t);
        while(t--) {
            printf("Case #%d: ", cas++);
            solve();
        }
        return 0;
    }
    

      

  • 相关阅读:
    JOIN条件限制对结果记录的影响
    什么是linux?
    什么是操作系统?
    Internship settled!
    Python dict 调试技巧 —— 利用YAML存储dict内容
    c++ 异常处理
    C#可空类型
    C# 异常处理
    C#值类型与引用类型
    C# 类类型
  • 原文地址:https://www.cnblogs.com/ost-xg/p/7417862.html
Copyright © 2011-2022 走看看